braintrust 0.0.96 → 0.0.98

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.
package/dist/browser.js CHANGED
@@ -12,7 +12,7 @@ var DefaultAsyncLocalStorage = class {
12
12
  }
13
13
  };
14
14
  var iso = {
15
- getRepoStatus: async (_settings) => void 0,
15
+ getRepoInfo: async (_settings) => void 0,
16
16
  getPastNAncestors: async () => [],
17
17
  getEnv: (_name) => void 0,
18
18
  getCallerLocation: () => void 0,
@@ -70,9 +70,10 @@ function v4(options, buf, offset) {
70
70
  }
71
71
  var v4_default = v4;
72
72
 
73
- // ../core/js/dist/index.mjs
73
+ // ../core/js/dist/main/index.mjs
74
74
  var TRANSACTION_ID_FIELD = "_xact_id";
75
75
  var IS_MERGE_FIELD = "_is_merge";
76
+ var MERGE_PATHS_FIELD = "_merge_paths";
76
77
  var AUDIT_SOURCE_FIELD = "_audit_source";
77
78
  var AUDIT_METADATA_FIELD = "_audit_metadata";
78
79
  var VALID_SOURCES = ["app", "api", "external"];
@@ -131,6 +132,54 @@ function mergeRowBatch(rows) {
131
132
  out.push(...Object.values(rowGroups));
132
133
  return out;
133
134
  }
135
+ var DEFAULT_IS_LEGACY_DATASET = true;
136
+ function ensureDatasetRecord(r, legacy) {
137
+ if (legacy) {
138
+ return ensureLegacyDatasetRecord(r);
139
+ } else {
140
+ return ensureNewDatasetRecord(r);
141
+ }
142
+ }
143
+ function ensureLegacyDatasetRecord(r) {
144
+ if ("output" in r) {
145
+ return r;
146
+ }
147
+ const row = {
148
+ ...r,
149
+ output: r.expected
150
+ };
151
+ delete row.expected;
152
+ return row;
153
+ }
154
+ function ensureNewDatasetRecord(r) {
155
+ if ("expected" in r) {
156
+ return r;
157
+ }
158
+ const row = {
159
+ ...r,
160
+ expected: r.output
161
+ };
162
+ delete row.output;
163
+ return row;
164
+ }
165
+ function makeLegacyEvent(e) {
166
+ if (!("dataset_id" in e) || !("expected" in e)) {
167
+ return e;
168
+ }
169
+ const event = {
170
+ ...e,
171
+ output: e.expected
172
+ };
173
+ delete event.expected;
174
+ if (MERGE_PATHS_FIELD in event) {
175
+ for (const path of event[MERGE_PATHS_FIELD] || []) {
176
+ if (path.length > 0 && path[0] === "expected") {
177
+ path[0] = "output";
178
+ }
179
+ }
180
+ }
181
+ return event;
182
+ }
134
183
  var SpanTypeAttribute = /* @__PURE__ */ ((SpanTypeAttribute2) => {
135
184
  SpanTypeAttribute2["LLM"] = "llm";
136
185
  SpanTypeAttribute2["SCORE"] = "score";
@@ -596,6 +645,9 @@ var MaxRequestSize = 6 * 1024 * 1024;
596
645
  function constructJsonArray(items) {
597
646
  return `[${items.join(",")}]`;
598
647
  }
648
+ function constructLogs3Data(items) {
649
+ return `{"rows": ${constructJsonArray(items)}, "api_version": 2}`;
650
+ }
599
651
  var DefaultBatchSize = 100;
600
652
  var NumRetries = 3;
601
653
  function now() {
@@ -654,11 +706,20 @@ var BackgroundLogger = class {
654
706
  }
655
707
  postPromises.push(
656
708
  (async () => {
657
- const itemsS = constructJsonArray(items);
709
+ const dataS = constructLogs3Data(items);
658
710
  for (let i = 0; i < NumRetries; i++) {
659
711
  const startTime = now();
660
712
  try {
661
- return (await (await this.logConn.get()).post_json("logs", itemsS)).map((res) => res.id);
713
+ try {
714
+ return (await (await this.logConn.get()).post_json("logs3", dataS)).ids.map((res) => res.id);
715
+ } catch (e) {
716
+ const legacyDataS = constructJsonArray(
717
+ items.map(
718
+ (r) => JSON.stringify(makeLegacyEvent(JSON.parse(r)))
719
+ )
720
+ );
721
+ return (await (await this.logConn.get()).post_json("logs", legacyDataS)).map((res) => res.id);
722
+ }
662
723
  } catch (e) {
663
724
  const retryingText = i + 1 === NumRetries ? "" : " Retrying";
664
725
  const errMsg = (() => {
@@ -669,7 +730,7 @@ var BackgroundLogger = class {
669
730
  }
670
731
  })();
671
732
  console.warn(
672
- `log request failed. Elapsed time: ${(now() - startTime) / 1e3} seconds. Payload size: ${itemsS.length}. Error: ${errMsg}.${retryingText}`
733
+ `log request failed. Elapsed time: ${(now() - startTime) / 1e3} seconds. Payload size: ${dataS.length}. Error: ${errMsg}.${retryingText}`
673
734
  );
674
735
  }
675
736
  }
@@ -697,8 +758,21 @@ var BackgroundLogger = class {
697
758
  }
698
759
  }
699
760
  };
700
- function init(project, options = {}) {
761
+ function init(projectOrOptions, optionalOptions) {
762
+ const options = (() => {
763
+ if (typeof projectOrOptions === "string") {
764
+ return { ...optionalOptions, project: projectOrOptions };
765
+ } else {
766
+ if (optionalOptions !== void 0) {
767
+ throw new Error(
768
+ "Cannot specify options struct as both parameters. Must call either init(project, options) or init(options)."
769
+ );
770
+ }
771
+ return projectOrOptions;
772
+ }
773
+ })();
701
774
  const {
775
+ project,
702
776
  experiment,
703
777
  description,
704
778
  dataset,
@@ -710,42 +784,66 @@ function init(project, options = {}) {
710
784
  apiKey,
711
785
  orgName,
712
786
  metadata,
713
- gitMetadataSettings
714
- } = options || {};
715
- if (open) {
787
+ gitMetadataSettings,
788
+ projectId,
789
+ baseExperimentId,
790
+ repoInfo
791
+ } = options;
792
+ if (open && update) {
793
+ throw new Error("Cannot open and update an experiment at the same time");
794
+ }
795
+ if (open || update) {
716
796
  if (isEmpty(experiment)) {
717
- throw new Error("Cannot open an experiment without specifying its name");
718
- }
719
- if (update) {
720
- throw new Error("Cannot open and update an experiment at the same time");
797
+ const action = open ? "open" : "update";
798
+ throw new Error(
799
+ `Cannot ${action} an experiment without specifying its name`
800
+ );
721
801
  }
722
- const lazyMetadata2 = new LazyValue(async () => {
723
- await login({
724
- orgName,
725
- apiKey,
726
- appUrl
727
- });
728
- const args = {
729
- project_name: project,
730
- org_name: _state.orgName,
731
- experiment_name: experiment
732
- };
733
- const response = await _state.apiConn().post_json("api/experiment/get", args);
734
- if (response.length === 0) {
735
- throw new Error(
736
- `Experiment ${experiment} not found in project ${project}.`
737
- );
802
+ const lazyMetadata2 = new LazyValue(
803
+ async () => {
804
+ await login({
805
+ orgName,
806
+ apiKey,
807
+ appUrl
808
+ });
809
+ const args = {
810
+ project_name: project,
811
+ project_id: projectId,
812
+ org_name: _state.orgName,
813
+ experiment_name: experiment
814
+ };
815
+ const response = await _state.apiConn().post_json("api/experiment/get", args);
816
+ if (response.length === 0) {
817
+ throw new Error(
818
+ `Experiment ${experiment} not found in project ${projectId ?? project}.`
819
+ );
820
+ }
821
+ const info = response[0];
822
+ return {
823
+ project: {
824
+ id: info.project_id,
825
+ name: "",
826
+ fullInfo: {}
827
+ },
828
+ experiment: {
829
+ id: info.id,
830
+ name: info.name,
831
+ fullInfo: info
832
+ }
833
+ };
738
834
  }
739
- const info = response[0];
740
- return {
741
- id: info.id,
742
- name: info.name,
743
- fullInfo: info
744
- };
745
- });
746
- return new ReadonlyExperiment(
747
- lazyMetadata2
748
835
  );
836
+ if (open) {
837
+ return new ReadonlyExperiment(
838
+ lazyMetadata2
839
+ );
840
+ } else {
841
+ const ret2 = new Experiment(lazyMetadata2, dataset);
842
+ if (options.setCurrent ?? true) {
843
+ _state.currentExperiment = ret2;
844
+ }
845
+ return ret2;
846
+ }
749
847
  }
750
848
  const lazyMetadata = new LazyValue(
751
849
  async () => {
@@ -756,6 +854,7 @@ function init(project, options = {}) {
756
854
  });
757
855
  const args = {
758
856
  project_name: project,
857
+ project_id: projectId,
759
858
  org_id: _state.orgId
760
859
  };
761
860
  if (experiment) {
@@ -764,25 +863,29 @@ function init(project, options = {}) {
764
863
  if (description) {
765
864
  args["description"] = description;
766
865
  }
767
- if (update) {
768
- args["update"] = update;
769
- }
770
- let mergedGitMetadataSettings = {
771
- ..._state.gitMetadataSettings || {
772
- collect: "all"
866
+ const repoInfoArg = await (async () => {
867
+ if (repoInfo) {
868
+ return repoInfo;
773
869
  }
774
- };
775
- if (gitMetadataSettings) {
776
- mergedGitMetadataSettings = mergeGitMetadataSettings(
777
- mergedGitMetadataSettings,
778
- gitMetadataSettings
779
- );
780
- }
781
- const repoStatus = await isomorph_default.getRepoStatus(gitMetadataSettings);
782
- if (repoStatus) {
783
- args["repo_info"] = repoStatus;
870
+ let mergedGitMetadataSettings = {
871
+ ..._state.gitMetadataSettings || {
872
+ collect: "all"
873
+ }
874
+ };
875
+ if (gitMetadataSettings) {
876
+ mergedGitMetadataSettings = mergeGitMetadataSettings(
877
+ mergedGitMetadataSettings,
878
+ gitMetadataSettings
879
+ );
880
+ }
881
+ return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
882
+ })();
883
+ if (repoInfoArg) {
884
+ args["repo_info"] = repoInfoArg;
784
885
  }
785
- if (baseExperiment) {
886
+ if (baseExperimentId) {
887
+ args["base_exp_id"] = baseExperimentId;
888
+ } else if (baseExperiment) {
786
889
  args["base_experiment"] = baseExperiment;
787
890
  } else {
788
891
  args["ancestor_commits"] = await isomorph_default.getPastNAncestors();
@@ -833,6 +936,21 @@ function init(project, options = {}) {
833
936
  }
834
937
  return ret;
835
938
  }
939
+ function initExperiment(projectOrOptions, optionalOptions) {
940
+ const options = (() => {
941
+ if (typeof projectOrOptions === "string") {
942
+ return { ...optionalOptions, project: projectOrOptions };
943
+ } else {
944
+ if (optionalOptions !== void 0) {
945
+ throw new Error(
946
+ "Cannot specify options struct as both parameters. Must call either init(project, options) or init(options)."
947
+ );
948
+ }
949
+ return projectOrOptions;
950
+ }
951
+ })();
952
+ return init(options);
953
+ }
836
954
  function withExperiment(project, callback, options = {}) {
837
955
  console.warn(
838
956
  "withExperiment is deprecated and will be removed in a future version of braintrust. Simply create the experiment with `init`."
@@ -847,8 +965,30 @@ function withLogger(callback, options = {}) {
847
965
  const logger = initLogger(options);
848
966
  return callback(logger);
849
967
  }
850
- function initDataset(project, options = {}) {
851
- const { dataset, description, version, appUrl, apiKey, orgName } = options || {};
968
+ function initDataset(projectOrOptions, optionalOptions) {
969
+ const options = (() => {
970
+ if (typeof projectOrOptions === "string") {
971
+ return { ...optionalOptions, project: projectOrOptions };
972
+ } else {
973
+ if (optionalOptions !== void 0) {
974
+ throw new Error(
975
+ "Cannot specify options struct as both parameters. Must call either initDataset(project, options) or initDataset(options)."
976
+ );
977
+ }
978
+ return projectOrOptions;
979
+ }
980
+ })();
981
+ const {
982
+ project,
983
+ dataset,
984
+ description,
985
+ version,
986
+ appUrl,
987
+ apiKey,
988
+ orgName,
989
+ projectId,
990
+ useOutput: legacy
991
+ } = options;
852
992
  const lazyMetadata = new LazyValue(
853
993
  async () => {
854
994
  await login({
@@ -859,6 +999,7 @@ function initDataset(project, options = {}) {
859
999
  const args = {
860
1000
  org_id: _state.orgId,
861
1001
  project_name: project,
1002
+ project_id: projectId,
862
1003
  dataset_name: dataset,
863
1004
  description
864
1005
  };
@@ -877,7 +1018,7 @@ function initDataset(project, options = {}) {
877
1018
  };
878
1019
  }
879
1020
  );
880
- return new Dataset(lazyMetadata, version);
1021
+ return new Dataset(lazyMetadata, version, legacy);
881
1022
  }
882
1023
  function withDataset(project, callback, options = {}) {
883
1024
  console.warn(
@@ -947,15 +1088,27 @@ function initLogger(options = {}) {
947
1088
  return ret;
948
1089
  }
949
1090
  async function login(options = {}) {
1091
+ let { forceLogin = false } = options || {};
1092
+ if (_state.loggedIn && !forceLogin) {
1093
+ let checkUpdatedParam2 = function(varname, arg, orig) {
1094
+ if (!isEmpty(arg) && !isEmpty(orig) && arg !== orig) {
1095
+ throw new Error(
1096
+ `Re-logging in with different ${varname} (${arg}) than original (${orig}). To force re-login, pass \`forceLogin: true\``
1097
+ );
1098
+ }
1099
+ };
1100
+ var checkUpdatedParam = checkUpdatedParam2;
1101
+ ;
1102
+ checkUpdatedParam2("appUrl", options.appUrl, _state.appUrl);
1103
+ checkUpdatedParam2("apiKey", options.apiKey ? HTTPConnection.sanitize_token(options.apiKey) : void 0, _state.loginToken);
1104
+ checkUpdatedParam2("orgName", options.orgName, _state.orgName);
1105
+ return;
1106
+ }
950
1107
  const {
951
1108
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrustdata.com",
952
1109
  apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
953
1110
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME")
954
1111
  } = options || {};
955
- let { forceLogin = false } = options || {};
956
- if (_state.loggedIn && !forceLogin) {
957
- return;
958
- }
959
1112
  _state.resetLoginInfo();
960
1113
  _state.appUrl = appUrl;
961
1114
  let conn = null;
@@ -1164,9 +1317,10 @@ function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
1164
1317
  return event;
1165
1318
  }
1166
1319
  var ObjectFetcher = class {
1167
- constructor(objectType, pinnedVersion) {
1320
+ constructor(objectType, pinnedVersion, mutateRecord) {
1168
1321
  this.objectType = objectType;
1169
1322
  this.pinnedVersion = pinnedVersion;
1323
+ this.mutateRecord = mutateRecord;
1170
1324
  this._fetchedData = void 0;
1171
1325
  }
1172
1326
  get id() {
@@ -1181,18 +1335,30 @@ var ObjectFetcher = class {
1181
1335
  yield record;
1182
1336
  }
1183
1337
  }
1184
- [Symbol.iterator]() {
1338
+ [Symbol.asyncIterator]() {
1185
1339
  return this.fetch();
1186
1340
  }
1187
1341
  async fetchedData() {
1188
1342
  if (this._fetchedData === void 0) {
1189
1343
  const state = await this.getState();
1190
- const resp = await state.logConn().get(`object/${this.objectType}`, {
1191
- id: await this.id,
1192
- fmt: "json2",
1193
- version: this.pinnedVersion
1194
- });
1195
- this._fetchedData = await resp.json();
1344
+ let data = void 0;
1345
+ try {
1346
+ const resp = await state.logConn().get(`object3/${this.objectType}`, {
1347
+ id: await this.id,
1348
+ fmt: "json2",
1349
+ version: this.pinnedVersion,
1350
+ api_version: "2"
1351
+ });
1352
+ data = await resp.json();
1353
+ } catch (e) {
1354
+ const resp = await state.logConn().get(`object/${this.objectType}`, {
1355
+ id: await this.id,
1356
+ fmt: "json2",
1357
+ version: this.pinnedVersion
1358
+ });
1359
+ data = await resp.json();
1360
+ }
1361
+ this._fetchedData = this.mutateRecord ? data?.map(this.mutateRecord) : data;
1196
1362
  }
1197
1363
  return this._fetchedData || [];
1198
1364
  }
@@ -1423,12 +1589,12 @@ var ReadonlyExperiment = class extends ObjectFetcher {
1423
1589
  }
1424
1590
  get id() {
1425
1591
  return (async () => {
1426
- return (await this.lazyMetadata.get()).id;
1592
+ return (await this.lazyMetadata.get()).experiment.id;
1427
1593
  })();
1428
1594
  }
1429
1595
  get name() {
1430
1596
  return (async () => {
1431
- return (await this.lazyMetadata.get()).name;
1597
+ return (await this.lazyMetadata.get()).experiment.name;
1432
1598
  })();
1433
1599
  }
1434
1600
  async getState() {
@@ -1441,11 +1607,18 @@ var ReadonlyExperiment = class extends ObjectFetcher {
1441
1607
  if (record.root_span_id !== record.span_id) {
1442
1608
  continue;
1443
1609
  }
1444
- const { output, expected } = record;
1445
- yield {
1446
- input: record.input,
1447
- expected: expected ?? output
1448
- };
1610
+ const { output, expected: expectedRecord } = record;
1611
+ const expected = expectedRecord ?? output;
1612
+ if (isEmpty(expected)) {
1613
+ yield {
1614
+ input: record.input
1615
+ };
1616
+ } else {
1617
+ yield {
1618
+ input: record.input,
1619
+ expected
1620
+ };
1621
+ }
1449
1622
  }
1450
1623
  }
1451
1624
  };
@@ -1578,8 +1751,18 @@ var SpanImpl = class _SpanImpl {
1578
1751
  }
1579
1752
  };
1580
1753
  var Dataset = class extends ObjectFetcher {
1581
- constructor(lazyMetadata, pinnedVersion) {
1582
- super("dataset", pinnedVersion);
1754
+ constructor(lazyMetadata, pinnedVersion, legacy) {
1755
+ const isLegacyDataset = legacy ?? DEFAULT_IS_LEGACY_DATASET;
1756
+ if (isLegacyDataset) {
1757
+ console.warn(
1758
+ `Records will be fetched from this dataset in the legacy format, with the "expected" field renamed to "output". Please update your code to use "expected", and use \`braintrust.initDataset()\` with \`{ useOutput: false }\`, which will become the default in a future version of Braintrust.`
1759
+ );
1760
+ }
1761
+ super(
1762
+ "dataset",
1763
+ pinnedVersion,
1764
+ (r) => ensureDatasetRecord(r, isLegacyDataset)
1765
+ );
1583
1766
  this.lazyMetadata = lazyMetadata;
1584
1767
  const logConn = new LazyValue(
1585
1768
  () => this.getState().then((state) => state.logConn())
@@ -1611,19 +1794,21 @@ var Dataset = class extends ObjectFetcher {
1611
1794
  *
1612
1795
  * @param event The event to log.
1613
1796
  * @param event.input The argument that uniquely define an input case (an arbitrary, JSON serializable object).
1614
- * @param event.output The output of your application, including post-processing (an arbitrary, JSON serializable object).
1797
+ * @param event.expected The output of your application, including post-processing (an arbitrary, JSON serializable object).
1615
1798
  * @param event.metadata (Optional) a dictionary with additional data about the test example, model outputs, or just
1616
1799
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
1617
1800
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
1618
1801
  * JSON-serializable type, but its keys must be strings.
1619
1802
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
1803
+ * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
1620
1804
  * @returns The `id` of the logged record.
1621
1805
  */
1622
1806
  insert({
1623
1807
  input,
1624
- output,
1808
+ expected,
1625
1809
  metadata,
1626
- id
1810
+ id,
1811
+ output
1627
1812
  }) {
1628
1813
  if (metadata !== void 0) {
1629
1814
  for (const key of Object.keys(metadata)) {
@@ -1632,11 +1817,16 @@ var Dataset = class extends ObjectFetcher {
1632
1817
  }
1633
1818
  }
1634
1819
  }
1820
+ if (expected && output) {
1821
+ throw new Error(
1822
+ "Only one of expected or output (deprecated) can be specified. Prefer expected."
1823
+ );
1824
+ }
1635
1825
  const rowId = id || v4_default();
1636
1826
  const args = new LazyValue(async () => ({
1637
1827
  id: rowId,
1638
- inputs: input,
1639
- output,
1828
+ input,
1829
+ expected: expected === void 0 ? output : expected,
1640
1830
  project_id: (await this.project).id,
1641
1831
  dataset_id: await this.id,
1642
1832
  created: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1955,7 +2145,6 @@ var WrapperStream = class {
1955
2145
  // src/browser.ts
1956
2146
  configureBrowser();
1957
2147
  export {
1958
- Dataset,
1959
2148
  Experiment,
1960
2149
  Logger,
1961
2150
  NOOP_SPAN,
@@ -1970,6 +2159,7 @@ export {
1970
2159
  getSpanParentObject,
1971
2160
  init,
1972
2161
  initDataset,
2162
+ initExperiment,
1973
2163
  initLogger,
1974
2164
  log,
1975
2165
  login,