braintrust 3.12.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dev/dist/index.d.mts +25 -6
  2. package/dev/dist/index.d.ts +25 -6
  3. package/dev/dist/index.js +134 -43
  4. package/dev/dist/index.mjs +113 -22
  5. package/dist/apply-auto-instrumentation.js +170 -170
  6. package/dist/apply-auto-instrumentation.mjs +1 -1
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +1 -0
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +1 -0
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +1 -0
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +1 -0
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +1 -0
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +1 -0
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  18. package/dist/auto-instrumentations/{chunk-2DPA74KK.mjs → chunk-E5DUYJWK.mjs} +1 -0
  19. package/dist/auto-instrumentations/{chunk-73BZUKVI.mjs → chunk-GJOO4ESL.mjs} +1 -1
  20. package/dist/auto-instrumentations/{chunk-AFXRW7I7.mjs → chunk-WFEUJACP.mjs} +1 -1
  21. package/dist/auto-instrumentations/hook.mjs +1 -0
  22. package/dist/auto-instrumentations/index.cjs +1 -0
  23. package/dist/auto-instrumentations/index.mjs +1 -1
  24. package/dist/browser.d.mts +149 -21
  25. package/dist/browser.d.ts +149 -21
  26. package/dist/browser.js +114 -24
  27. package/dist/browser.mjs +114 -24
  28. package/dist/{chunk-BW4DF4CY.js → chunk-26JGOELH.js} +1 -0
  29. package/dist/{chunk-MSLBGITU.mjs → chunk-75IQCUB2.mjs} +1 -0
  30. package/dist/cli.js +121 -44
  31. package/dist/edge-light.d.mts +1 -1
  32. package/dist/edge-light.d.ts +1 -1
  33. package/dist/edge-light.js +114 -24
  34. package/dist/edge-light.mjs +114 -24
  35. package/dist/index.d.mts +149 -21
  36. package/dist/index.d.ts +149 -21
  37. package/dist/index.js +529 -394
  38. package/dist/index.mjs +161 -26
  39. package/dist/instrumentation/index.d.mts +40 -3
  40. package/dist/instrumentation/index.d.ts +40 -3
  41. package/dist/instrumentation/index.js +15 -2
  42. package/dist/instrumentation/index.mjs +15 -2
  43. package/dist/workerd.d.mts +1 -1
  44. package/dist/workerd.d.ts +1 -1
  45. package/dist/workerd.js +114 -24
  46. package/dist/workerd.mjs +114 -24
  47. package/package.json +3 -17
  48. package/util/dist/index.d.mts +3 -1
  49. package/util/dist/index.d.ts +3 -1
@@ -96,6 +96,7 @@ import * as fsSync from "node:fs";
96
96
  import * as crypto from "node:crypto";
97
97
  import { promisify } from "node:util";
98
98
  import * as zlib from "node:zlib";
99
+ import * as dotenv from "dotenv";
99
100
 
100
101
  // src/isomorph.ts
101
102
  var DefaultAsyncLocalStorage = class {
@@ -182,6 +183,7 @@ var iso = {
182
183
  getRepoInfo: async (_settings) => void 0,
183
184
  getPastNAncestors: async () => [],
184
185
  getEnv: (_name) => void 0,
186
+ getBraintrustApiKey: async () => void 0,
185
187
  getCallerLocation: () => void 0,
186
188
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
187
189
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -7266,10 +7268,11 @@ async function login(options = {}) {
7266
7268
  async function loginToState(options = {}) {
7267
7269
  const {
7268
7270
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7269
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7271
+ apiKey: apiKeyArg,
7270
7272
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7271
7273
  fetch: fetch2 = globalThis.fetch
7272
7274
  } = options || {};
7275
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7273
7276
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7274
7277
  const state = new BraintrustState(options);
7275
7278
  state.resetLoginInfo();
@@ -8288,9 +8291,15 @@ var SpanImpl = class _SpanImpl {
8288
8291
  const cachedSpan = {
8289
8292
  input: partialRecord.input,
8290
8293
  output: partialRecord.output,
8294
+ expected: partialRecord.expected,
8295
+ error: partialRecord.error,
8296
+ scores: partialRecord.scores,
8297
+ metrics: partialRecord.metrics,
8291
8298
  metadata: partialRecord.metadata,
8299
+ tags: partialRecord.tags,
8292
8300
  span_id: this._spanId,
8293
8301
  span_parents: this._spanParents,
8302
+ is_root: this._spanId === this._rootSpanId,
8294
8303
  span_attributes: partialRecord.span_attributes
8295
8304
  };
8296
8305
  this._state.spanCache.queueWrite(
@@ -8626,6 +8635,7 @@ var Dataset2 = class extends ObjectFetcher {
8626
8635
  metadata,
8627
8636
  tags,
8628
8637
  output,
8638
+ origin,
8629
8639
  isMerge
8630
8640
  }) {
8631
8641
  return new LazyValue(async () => {
@@ -8640,6 +8650,7 @@ var Dataset2 = class extends ObjectFetcher {
8640
8650
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
8641
8651
  //if we're merging/updating an event we will not add this ts
8642
8652
  metadata,
8653
+ origin,
8643
8654
  ...!!isMerge ? {
8644
8655
  [IS_MERGE_FIELD]: true
8645
8656
  } : {}
@@ -8659,6 +8670,7 @@ var Dataset2 = class extends ObjectFetcher {
8659
8670
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
8660
8671
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
8661
8672
  * JSON-serializable type, but its keys must be strings.
8673
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
8662
8674
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
8663
8675
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
8664
8676
  * @returns The `id` of the logged record.
@@ -8669,7 +8681,8 @@ var Dataset2 = class extends ObjectFetcher {
8669
8681
  metadata,
8670
8682
  tags,
8671
8683
  id,
8672
- output
8684
+ output,
8685
+ origin
8673
8686
  }) {
8674
8687
  this.validateEvent({ metadata, expected, output, tags });
8675
8688
  const rowId = id || uuidv42();
@@ -8681,6 +8694,7 @@ var Dataset2 = class extends ObjectFetcher {
8681
8694
  metadata,
8682
8695
  tags,
8683
8696
  output,
8697
+ origin,
8684
8698
  isMerge: false
8685
8699
  })
8686
8700
  );
@@ -25411,11 +25425,60 @@ var PluginRegistry = class {
25411
25425
  var registry = new PluginRegistry();
25412
25426
 
25413
25427
  // src/node/config.ts
25428
+ var BRAINTRUST_ENV_SEARCH_PARENT_LIMIT = 64;
25414
25429
  function configureNode() {
25415
25430
  isomorph_default.buildType = "node";
25416
25431
  isomorph_default.getRepoInfo = getRepoInfo;
25417
25432
  isomorph_default.getPastNAncestors = getPastNAncestors;
25418
- isomorph_default.getEnv = (name) => process.env[name];
25433
+ isomorph_default.getEnv = (name) => {
25434
+ const value = process.env[name];
25435
+ return name === "BRAINTRUST_API_KEY" && !value?.trim() ? void 0 : value;
25436
+ };
25437
+ isomorph_default.getBraintrustApiKey = async () => {
25438
+ const value = process.env.BRAINTRUST_API_KEY;
25439
+ if (value?.trim()) {
25440
+ return value;
25441
+ }
25442
+ const envPaths = [];
25443
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
25444
+ envPaths.push(path.join(dir2, ".env.braintrust"));
25445
+ if (path.dirname(dir2) === dir2) {
25446
+ break;
25447
+ }
25448
+ }
25449
+ const pending = /* @__PURE__ */ new Map();
25450
+ envPaths.forEach((envPath, index) => {
25451
+ pending.set(
25452
+ index,
25453
+ fs.readFile(envPath, "utf8").then(
25454
+ (contents) => ({ contents, envPath, index }),
25455
+ (error) => ({ error, envPath, index })
25456
+ )
25457
+ );
25458
+ });
25459
+ const results = [];
25460
+ let nearestUnresolvedIndex = 0;
25461
+ while (pending.size > 0) {
25462
+ const result = await Promise.race(pending.values());
25463
+ pending.delete(result.index);
25464
+ results[result.index] = result;
25465
+ while (results[nearestUnresolvedIndex]) {
25466
+ const nearestResult = results[nearestUnresolvedIndex];
25467
+ if ("contents" in nearestResult) {
25468
+ const parsed = dotenv.parse(nearestResult.contents);
25469
+ const apiKey = parsed.BRAINTRUST_API_KEY;
25470
+ return apiKey?.trim() ? apiKey : void 0;
25471
+ }
25472
+ const e = nearestResult.error;
25473
+ if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT") {
25474
+ nearestUnresolvedIndex++;
25475
+ continue;
25476
+ }
25477
+ return void 0;
25478
+ }
25479
+ }
25480
+ return void 0;
25481
+ };
25419
25482
  isomorph_default.getCallerLocation = getCallerLocation;
25420
25483
  isomorph_default.newAsyncLocalStorage = () => new AsyncLocalStorage();
25421
25484
  isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
@@ -26570,8 +26633,12 @@ async function invoke(args) {
26570
26633
 
26571
26634
  // src/trace.ts
26572
26635
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
26573
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
26574
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
26636
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
26637
+ const filterExpr = _SpanFetcher.buildFilter(
26638
+ rootSpanId,
26639
+ spanTypeFilter,
26640
+ includeScorers
26641
+ );
26575
26642
  super(objectType, void 0, void 0, {
26576
26643
  filter: filterExpr
26577
26644
  });
@@ -26580,16 +26647,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
26580
26647
  this._state = _state;
26581
26648
  this.spanTypeFilter = spanTypeFilter;
26582
26649
  }
26583
- static buildFilter(rootSpanId, spanTypeFilter) {
26650
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
26584
26651
  const children = [
26585
26652
  // Base filter: root_span_id = 'value'
26586
26653
  {
26587
26654
  op: "eq",
26588
26655
  left: { op: "ident", name: ["root_span_id"] },
26589
26656
  right: { op: "literal", value: rootSpanId }
26590
- },
26591
- // Exclude span_attributes.purpose = 'score'
26592
- {
26657
+ }
26658
+ ];
26659
+ if (!includeScorers) {
26660
+ children.push({
26593
26661
  op: "or",
26594
26662
  children: [
26595
26663
  {
@@ -26602,8 +26670,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
26602
26670
  right: { op: "literal", value: "scorer" }
26603
26671
  }
26604
26672
  ]
26605
- }
26606
- ];
26673
+ });
26674
+ }
26607
26675
  if (spanTypeFilter && spanTypeFilter.length > 0) {
26608
26676
  children.push({
26609
26677
  op: "in",
@@ -26629,35 +26697,49 @@ var CachedSpanFetcher = class {
26629
26697
  fetchFn;
26630
26698
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
26631
26699
  if (typeof objectTypeOrFetchFn === "function") {
26632
- this.fetchFn = objectTypeOrFetchFn;
26700
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
26633
26701
  } else {
26634
26702
  const objectType = objectTypeOrFetchFn;
26635
- this.fetchFn = async (spanType) => {
26703
+ this.fetchFn = async (spanType, includeScorers) => {
26636
26704
  const state = await getState();
26637
26705
  const fetcher = new SpanFetcher(
26638
26706
  objectType,
26639
26707
  objectId,
26640
26708
  rootSpanId,
26641
26709
  state,
26642
- spanType
26710
+ spanType,
26711
+ includeScorers
26643
26712
  );
26644
26713
  const rows = await fetcher.fetchedData();
26645
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
26714
+ return rows.map((row) => ({
26646
26715
  input: row.input,
26647
26716
  output: row.output,
26717
+ expected: row.expected,
26718
+ error: row.error,
26719
+ scores: row.scores,
26720
+ metrics: row.metrics,
26648
26721
  metadata: row.metadata,
26649
26722
  span_id: row.span_id,
26650
26723
  span_parents: row.span_parents,
26724
+ is_root: row.is_root,
26651
26725
  span_attributes: row.span_attributes,
26652
26726
  id: row.id,
26653
26727
  _xact_id: row._xact_id,
26654
26728
  _pagination_key: row._pagination_key,
26655
- root_span_id: row.root_span_id
26729
+ root_span_id: row.root_span_id,
26730
+ created: row.created,
26731
+ tags: row.tags
26656
26732
  }));
26657
26733
  };
26658
26734
  }
26659
26735
  }
26660
- async getSpans({ spanType } = {}) {
26736
+ async getSpans({
26737
+ spanType,
26738
+ includeScorers = false
26739
+ } = {}) {
26740
+ if (includeScorers) {
26741
+ return this.fetchFn(spanType, true);
26742
+ }
26661
26743
  if (this.allFetched) {
26662
26744
  return this.getFromCache(spanType);
26663
26745
  }
@@ -26674,7 +26756,7 @@ var CachedSpanFetcher = class {
26674
26756
  return this.getFromCache(spanType);
26675
26757
  }
26676
26758
  async fetchSpans(spanType) {
26677
- const spans = await this.fetchFn(spanType);
26759
+ const spans = await this.fetchFn(spanType, false);
26678
26760
  for (const span of spans) {
26679
26761
  const type = span.span_attributes?.type ?? "";
26680
26762
  const existing = this.spanCache.get(type) ?? [];
@@ -26752,10 +26834,13 @@ var LocalTrace = class {
26752
26834
  * First checks the local span cache for recently logged spans, then falls
26753
26835
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
26754
26836
  */
26755
- async getSpans({ spanType } = {}) {
26837
+ async getSpans({
26838
+ spanType,
26839
+ includeScorers = false
26840
+ } = {}) {
26756
26841
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
26757
26842
  if (cachedSpans && cachedSpans.length > 0) {
26758
- let spans = cachedSpans.filter(
26843
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
26759
26844
  (span) => span.span_attributes?.purpose !== "scorer"
26760
26845
  );
26761
26846
  if (spanType && spanType.length > 0) {
@@ -26766,13 +26851,19 @@ var LocalTrace = class {
26766
26851
  return spans.map((span) => ({
26767
26852
  input: span.input,
26768
26853
  output: span.output,
26854
+ expected: span.expected,
26855
+ error: span.error,
26856
+ scores: span.scores,
26857
+ metrics: span.metrics,
26769
26858
  metadata: span.metadata,
26770
26859
  span_id: span.span_id,
26771
26860
  span_parents: span.span_parents,
26772
- span_attributes: span.span_attributes
26861
+ is_root: span.is_root,
26862
+ span_attributes: span.span_attributes,
26863
+ tags: span.tags
26773
26864
  }));
26774
26865
  }
26775
- return this.cachedFetcher.getSpans({ spanType });
26866
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
26776
26867
  }
26777
26868
  /**
26778
26869
  * Get the thread (preprocessed messages) for this trace.