braintrust 0.0.94 → 0.0.95

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
@@ -704,6 +704,7 @@ function init(project, options = {}) {
704
704
  dataset,
705
705
  baseExperiment,
706
706
  isPublic,
707
+ open,
707
708
  update,
708
709
  appUrl,
709
710
  apiKey,
@@ -711,6 +712,41 @@ function init(project, options = {}) {
711
712
  metadata,
712
713
  gitMetadataSettings
713
714
  } = options || {};
715
+ if (open) {
716
+ 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");
721
+ }
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
+ );
738
+ }
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
+ );
749
+ }
714
750
  const lazyMetadata = new LazyValue(
715
751
  async () => {
716
752
  await login({
@@ -752,7 +788,7 @@ function init(project, options = {}) {
752
788
  args["ancestor_commits"] = await isomorph_default.getPastNAncestors();
753
789
  }
754
790
  if (dataset !== void 0) {
755
- args["dataset_id"] = dataset.id;
791
+ args["dataset_id"] = await dataset.id;
756
792
  args["dataset_version"] = await dataset.version();
757
793
  }
758
794
  if (isPublic !== void 0) {
@@ -1107,15 +1143,15 @@ function validateAndSanitizeExperimentLogPartialArgs(event) {
1107
1143
  }
1108
1144
  }
1109
1145
  function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
1110
- if ("input" in event && event.input && "inputs" in event && event.inputs || !("input" in event) && !("inputs" in event)) {
1146
+ if ("input" in event && !isEmpty(event.input) && "inputs" in event && !isEmpty(event.inputs) || !("input" in event) && !("inputs" in event)) {
1111
1147
  throw new Error(
1112
1148
  "Exactly one of input or inputs (deprecated) must be specified. Prefer input."
1113
1149
  );
1114
1150
  }
1115
- if (!event.output) {
1151
+ if (isEmpty(event.output)) {
1116
1152
  throw new Error("output must be specified");
1117
1153
  }
1118
- if (!event.scores) {
1154
+ if (isEmpty(event.scores)) {
1119
1155
  throw new Error("scores must be specified");
1120
1156
  }
1121
1157
  if (hasDataset && event.datasetRecordId === void 0) {
@@ -1127,8 +1163,61 @@ function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
1127
1163
  }
1128
1164
  return event;
1129
1165
  }
1130
- var Experiment = class {
1166
+ var ObjectFetcher = class {
1167
+ constructor(objectType, pinnedVersion) {
1168
+ this.objectType = objectType;
1169
+ this.pinnedVersion = pinnedVersion;
1170
+ this._fetchedData = void 0;
1171
+ }
1172
+ get id() {
1173
+ throw new Error("ObjectFetcher subclasses must have an 'id' attribute");
1174
+ }
1175
+ async getState() {
1176
+ throw new Error("ObjectFetcher subclasses must have a 'getState' method");
1177
+ }
1178
+ async *fetch() {
1179
+ const records = await this.fetchedData();
1180
+ for (const record of records) {
1181
+ yield record;
1182
+ }
1183
+ }
1184
+ [Symbol.iterator]() {
1185
+ return this.fetch();
1186
+ }
1187
+ async fetchedData() {
1188
+ if (this._fetchedData === void 0) {
1189
+ 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();
1196
+ }
1197
+ return this._fetchedData || [];
1198
+ }
1199
+ clearCache() {
1200
+ this._fetchedData = void 0;
1201
+ }
1202
+ async version() {
1203
+ if (this.pinnedVersion !== void 0) {
1204
+ return this.pinnedVersion;
1205
+ } else {
1206
+ const fetchedData = await this.fetchedData();
1207
+ let maxVersion = void 0;
1208
+ for (const record of fetchedData) {
1209
+ const xactId = record[TRANSACTION_ID_FIELD];
1210
+ if (maxVersion === void 0 || (xactId ?? xactId > maxVersion)) {
1211
+ maxVersion = xactId;
1212
+ }
1213
+ }
1214
+ return maxVersion;
1215
+ }
1216
+ }
1217
+ };
1218
+ var Experiment = class extends ObjectFetcher {
1131
1219
  constructor(lazyMetadata, dataset) {
1220
+ super("experiment", void 0);
1132
1221
  // For type identification.
1133
1222
  this.kind = "experiment";
1134
1223
  this.lazyMetadata = lazyMetadata;
@@ -1221,6 +1310,26 @@ var Experiment = class {
1221
1310
  ...argsRest
1222
1311
  });
1223
1312
  }
1313
+ async fetchBaseExperiment() {
1314
+ const state = await this.getState();
1315
+ const conn = state.apiConn();
1316
+ try {
1317
+ const resp = await conn.post("/api/base_experiment/get_id", {
1318
+ id: await this.id
1319
+ });
1320
+ const base = await resp.json();
1321
+ return {
1322
+ id: base["base_exp_id"],
1323
+ name: base["base_exp_name"]
1324
+ };
1325
+ } catch (e) {
1326
+ if (e instanceof FailedHTTPResponse && e.status === 400) {
1327
+ return null;
1328
+ } else {
1329
+ throw e;
1330
+ }
1331
+ }
1332
+ }
1224
1333
  /**
1225
1334
  * Summarize the experiment, including the scores (compared to the closest reference experiment) and metadata.
1226
1335
  *
@@ -1244,14 +1353,10 @@ var Experiment = class {
1244
1353
  let comparisonExperimentName = void 0;
1245
1354
  if (summarizeScores) {
1246
1355
  if (comparisonExperimentId === void 0) {
1247
- const conn = state.logConn();
1248
- const resp = await conn.get("/crud/base_experiments", {
1249
- id: await this.id
1250
- });
1251
- const base_experiments = await resp.json();
1252
- if (base_experiments.length > 0) {
1253
- comparisonExperimentId = base_experiments[0]["base_exp_id"];
1254
- comparisonExperimentName = base_experiments[0]["base_exp_name"];
1356
+ const baseExperiment = await this.fetchBaseExperiment();
1357
+ if (baseExperiment !== null) {
1358
+ comparisonExperimentId = baseExperiment.id;
1359
+ comparisonExperimentName = baseExperiment.name;
1255
1360
  }
1256
1361
  }
1257
1362
  if (comparisonExperimentId !== void 0) {
@@ -1311,6 +1416,40 @@ var Experiment = class {
1311
1416
  return this.id;
1312
1417
  }
1313
1418
  };
1419
+ var ReadonlyExperiment = class extends ObjectFetcher {
1420
+ constructor(lazyMetadata) {
1421
+ super("experiment", void 0);
1422
+ this.lazyMetadata = lazyMetadata;
1423
+ }
1424
+ get id() {
1425
+ return (async () => {
1426
+ return (await this.lazyMetadata.get()).id;
1427
+ })();
1428
+ }
1429
+ get name() {
1430
+ return (async () => {
1431
+ return (await this.lazyMetadata.get()).name;
1432
+ })();
1433
+ }
1434
+ async getState() {
1435
+ await this.lazyMetadata.get();
1436
+ return _state;
1437
+ }
1438
+ async *asDataset() {
1439
+ const records = this.fetch();
1440
+ for await (const record of records) {
1441
+ if (record.root_span_id !== record.span_id) {
1442
+ continue;
1443
+ }
1444
+ const { output, expected } = record;
1445
+ yield {
1446
+ input: record.input,
1447
+ expected: expected ?? output
1448
+ };
1449
+ }
1450
+ }
1451
+ };
1452
+ var executionCounter = 0;
1314
1453
  var SpanImpl = class _SpanImpl {
1315
1454
  // root_experiment should only be specified for a root span. parent_span
1316
1455
  // should only be specified for non-root spans.
@@ -1336,7 +1475,11 @@ var SpanImpl = class _SpanImpl {
1336
1475
  start: args.startTime ?? getCurrentUnixTimestamp()
1337
1476
  },
1338
1477
  context: { ...callerLocation },
1339
- span_attributes: { ...args.spanAttributes, name },
1478
+ span_attributes: {
1479
+ ...args.spanAttributes,
1480
+ name,
1481
+ exec_counter: executionCounter++
1482
+ },
1340
1483
  created: (/* @__PURE__ */ new Date()).toISOString()
1341
1484
  };
1342
1485
  this.parentIds = args.parentIds;
@@ -1434,11 +1577,10 @@ var SpanImpl = class _SpanImpl {
1434
1577
  return this.end(args);
1435
1578
  }
1436
1579
  };
1437
- var Dataset = class {
1580
+ var Dataset = class extends ObjectFetcher {
1438
1581
  constructor(lazyMetadata, pinnedVersion) {
1439
- this._fetchedData = void 0;
1582
+ super("dataset", pinnedVersion);
1440
1583
  this.lazyMetadata = lazyMetadata;
1441
- this.pinnedVersion = pinnedVersion;
1442
1584
  const logConn = new LazyValue(
1443
1585
  () => this.getState().then((state) => state.logConn())
1444
1586
  );
@@ -1546,81 +1688,6 @@ var Dataset = class {
1546
1688
  dataSummary
1547
1689
  };
1548
1690
  }
1549
- /**
1550
- * Fetch all records in the dataset.
1551
- *
1552
- * @example
1553
- * ```
1554
- * // Use an async iterator to fetch all records in the dataset.
1555
- * for await (const record of dataset.fetch()) {
1556
- * console.log(record);
1557
- * }
1558
- *
1559
- * // You can also iterate over the dataset directly.
1560
- * for await (const record of dataset) {
1561
- * console.log(record);
1562
- * }
1563
- * ```
1564
- *
1565
- * @returns An iterator over the dataset's records.
1566
- */
1567
- async *fetch() {
1568
- const records = await this.fetchedData();
1569
- for (const record of records) {
1570
- yield {
1571
- id: record.id,
1572
- input: record.input && JSON.parse(record.input),
1573
- output: record.input && JSON.parse(record.output),
1574
- metadata: record.metadata && JSON.parse(record.metadata)
1575
- };
1576
- }
1577
- this.clearCache();
1578
- }
1579
- /**
1580
- * Fetch all records in the dataset.
1581
- *
1582
- * @example
1583
- * ```
1584
- * // Use an async iterator to fetch all records in the dataset.
1585
- * for await (const record of dataset) {
1586
- * console.log(record);
1587
- * }
1588
- * ```
1589
- */
1590
- [Symbol.asyncIterator]() {
1591
- return this.fetch();
1592
- }
1593
- async fetchedData() {
1594
- if (this._fetchedData === void 0) {
1595
- const state = await this.getState();
1596
- const resp = await state.logConn().get("object/dataset", {
1597
- id: await this.id,
1598
- fmt: "json",
1599
- version: this.pinnedVersion
1600
- });
1601
- const text = await resp.text();
1602
- this._fetchedData = text.split("\n").filter((x) => x.trim() !== "").map((x) => JSON.parse(x));
1603
- }
1604
- return this._fetchedData || [];
1605
- }
1606
- clearCache() {
1607
- this._fetchedData = void 0;
1608
- }
1609
- async version() {
1610
- if (this.pinnedVersion !== void 0) {
1611
- return this.pinnedVersion;
1612
- } else {
1613
- const fetchedData = await this.fetchedData();
1614
- let maxVersion = void 0;
1615
- for (const record of fetchedData) {
1616
- const xactId = record[TRANSACTION_ID_FIELD];
1617
- if (maxVersion === void 0 || (xactId ?? xactId > maxVersion)) {
1618
- maxVersion = xactId;
1619
- }
1620
- }
1621
- return maxVersion;
1622
- }
1623
- }
1624
1691
  /**
1625
1692
  * Flush any pending rows to the server.
1626
1693
  */
@@ -1891,6 +1958,7 @@ export {
1891
1958
  Logger,
1892
1959
  NOOP_SPAN,
1893
1960
  NoopSpan,
1961
+ ReadonlyExperiment,
1894
1962
  SpanImpl,
1895
1963
  _internalGetGlobalState,
1896
1964
  _internalSetInitialState,