braintrust 0.0.93 → 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 +380 -266
- package/dist/cli.js +328 -317
- package/dist/framework.d.ts +21 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.js +435 -273
- package/dist/logger.d.ts +57 -51
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/util.d.ts +6 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -9065,7 +9065,7 @@ var require_package = __commonJS({
|
|
|
9065
9065
|
"package.json"(exports2, module2) {
|
|
9066
9066
|
module2.exports = {
|
|
9067
9067
|
name: "braintrust",
|
|
9068
|
-
version: "0.0.
|
|
9068
|
+
version: "0.0.95",
|
|
9069
9069
|
description: "SDK for integrating Braintrust",
|
|
9070
9070
|
main: "./dist/index.js",
|
|
9071
9071
|
browser: {
|
|
@@ -9108,7 +9108,7 @@ var require_package = __commonJS({
|
|
|
9108
9108
|
typescript: "^5.3.3"
|
|
9109
9109
|
},
|
|
9110
9110
|
dependencies: {
|
|
9111
|
-
"@braintrust/core": "^0.0.
|
|
9111
|
+
"@braintrust/core": "^0.0.14",
|
|
9112
9112
|
argparse: "^2.0.1",
|
|
9113
9113
|
chalk: "^4.1.2",
|
|
9114
9114
|
"cli-progress": "^3.12.0",
|
|
@@ -9128,7 +9128,7 @@ var esbuild = __toESM(require("esbuild"));
|
|
|
9128
9128
|
var import_fs = __toESM(require("fs"));
|
|
9129
9129
|
var import_os = __toESM(require("os"));
|
|
9130
9130
|
var import_path = __toESM(require("path"));
|
|
9131
|
-
var
|
|
9131
|
+
var import_util3 = __toESM(require("util"));
|
|
9132
9132
|
var fsWalk = __toESM(require_out3());
|
|
9133
9133
|
|
|
9134
9134
|
// ../../node_modules/.pnpm/minimatch@9.0.3/node_modules/minimatch/dist/mjs/index.js
|
|
@@ -10644,6 +10644,21 @@ function getCurrentUnixTimestamp() {
|
|
|
10644
10644
|
function isEmpty(a) {
|
|
10645
10645
|
return a === void 0 || a === null;
|
|
10646
10646
|
}
|
|
10647
|
+
var LazyValue = class {
|
|
10648
|
+
constructor(callable) {
|
|
10649
|
+
this.value = {
|
|
10650
|
+
hasComputed: false
|
|
10651
|
+
};
|
|
10652
|
+
this.callable = callable;
|
|
10653
|
+
}
|
|
10654
|
+
async get() {
|
|
10655
|
+
if (this.value.hasComputed) {
|
|
10656
|
+
return this.value.val;
|
|
10657
|
+
}
|
|
10658
|
+
this.value = { hasComputed: true, val: await this.callable() };
|
|
10659
|
+
return this.value.val;
|
|
10660
|
+
}
|
|
10661
|
+
};
|
|
10647
10662
|
|
|
10648
10663
|
// src/logger.ts
|
|
10649
10664
|
var NoopSpan = class {
|
|
@@ -10858,25 +10873,25 @@ function logFeedbackImpl(bgLogger, parentIds, {
|
|
|
10858
10873
|
updateEvent = Object.fromEntries(
|
|
10859
10874
|
Object.entries(updateEvent).filter(([_, v]) => !isEmpty(v))
|
|
10860
10875
|
);
|
|
10861
|
-
const trueParentIds = (async () => {
|
|
10862
|
-
const { kind, ...ids } = await parentIds;
|
|
10876
|
+
const trueParentIds = new LazyValue(async () => {
|
|
10877
|
+
const { kind, ...ids } = await parentIds.get();
|
|
10863
10878
|
return ids;
|
|
10864
|
-
})
|
|
10879
|
+
});
|
|
10865
10880
|
if (Object.keys(updateEvent).length > 0) {
|
|
10866
|
-
const record = (async () => {
|
|
10881
|
+
const record = new LazyValue(async () => {
|
|
10867
10882
|
return {
|
|
10868
10883
|
id,
|
|
10869
10884
|
...updateEvent,
|
|
10870
|
-
...await trueParentIds,
|
|
10885
|
+
...await trueParentIds.get(),
|
|
10871
10886
|
[AUDIT_SOURCE_FIELD]: source,
|
|
10872
10887
|
[AUDIT_METADATA_FIELD]: metadata,
|
|
10873
10888
|
[IS_MERGE_FIELD]: true
|
|
10874
10889
|
};
|
|
10875
|
-
})
|
|
10890
|
+
});
|
|
10876
10891
|
bgLogger.log([record]);
|
|
10877
10892
|
}
|
|
10878
10893
|
if (!isEmpty(comment)) {
|
|
10879
|
-
const record = (async () => {
|
|
10894
|
+
const record = new LazyValue(async () => {
|
|
10880
10895
|
return {
|
|
10881
10896
|
id: v4_default(),
|
|
10882
10897
|
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10888,11 +10903,11 @@ function logFeedbackImpl(bgLogger, parentIds, {
|
|
|
10888
10903
|
comment: {
|
|
10889
10904
|
text: comment
|
|
10890
10905
|
},
|
|
10891
|
-
...await trueParentIds,
|
|
10906
|
+
...await trueParentIds.get(),
|
|
10892
10907
|
[AUDIT_SOURCE_FIELD]: source,
|
|
10893
10908
|
[AUDIT_METADATA_FIELD]: metadata
|
|
10894
10909
|
};
|
|
10895
|
-
})
|
|
10910
|
+
});
|
|
10896
10911
|
bgLogger.log([record]);
|
|
10897
10912
|
}
|
|
10898
10913
|
}
|
|
@@ -10924,9 +10939,20 @@ var BackgroundLogger = class {
|
|
|
10924
10939
|
}
|
|
10925
10940
|
async flush_once(batchSize = DefaultBatchSize) {
|
|
10926
10941
|
this.active_flush_resolved = false;
|
|
10927
|
-
const
|
|
10942
|
+
const itemLazyValues = this.items;
|
|
10928
10943
|
this.items = [];
|
|
10929
|
-
const allItems =
|
|
10944
|
+
const allItems = await (async () => {
|
|
10945
|
+
try {
|
|
10946
|
+
const itemPromises = itemLazyValues.map((x) => x.get());
|
|
10947
|
+
return mergeRowBatch(await Promise.all(itemPromises)).reverse();
|
|
10948
|
+
} catch (e) {
|
|
10949
|
+
console.warn(
|
|
10950
|
+
"Encountered error when constructing records to flush:\n",
|
|
10951
|
+
e
|
|
10952
|
+
);
|
|
10953
|
+
return [];
|
|
10954
|
+
}
|
|
10955
|
+
})();
|
|
10930
10956
|
let postPromises = [];
|
|
10931
10957
|
while (true) {
|
|
10932
10958
|
const items = [];
|
|
@@ -10951,9 +10977,7 @@ var BackgroundLogger = class {
|
|
|
10951
10977
|
for (let i = 0; i < NumRetries; i++) {
|
|
10952
10978
|
const startTime = now();
|
|
10953
10979
|
try {
|
|
10954
|
-
return (await (await this.logConn).post_json("logs", itemsS)).map(
|
|
10955
|
-
(res) => res.id
|
|
10956
|
-
);
|
|
10980
|
+
return (await (await this.logConn.get()).post_json("logs", itemsS)).map((res) => res.id);
|
|
10957
10981
|
} catch (e) {
|
|
10958
10982
|
const retryingText = i + 1 === NumRetries ? "" : " Retrying";
|
|
10959
10983
|
const errMsg = (() => {
|
|
@@ -10999,6 +11023,7 @@ function init(project, options = {}) {
|
|
|
10999
11023
|
dataset,
|
|
11000
11024
|
baseExperiment,
|
|
11001
11025
|
isPublic,
|
|
11026
|
+
open,
|
|
11002
11027
|
update,
|
|
11003
11028
|
appUrl,
|
|
11004
11029
|
apiKey,
|
|
@@ -11006,82 +11031,121 @@ function init(project, options = {}) {
|
|
|
11006
11031
|
metadata,
|
|
11007
11032
|
gitMetadataSettings
|
|
11008
11033
|
} = options || {};
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
apiKey,
|
|
11013
|
-
appUrl
|
|
11014
|
-
});
|
|
11015
|
-
const args = {
|
|
11016
|
-
project_name: project,
|
|
11017
|
-
org_id: _state.orgId
|
|
11018
|
-
};
|
|
11019
|
-
if (experiment) {
|
|
11020
|
-
args["experiment_name"] = experiment;
|
|
11021
|
-
}
|
|
11022
|
-
if (description) {
|
|
11023
|
-
args["description"] = description;
|
|
11034
|
+
if (open) {
|
|
11035
|
+
if (isEmpty(experiment)) {
|
|
11036
|
+
throw new Error("Cannot open an experiment without specifying its name");
|
|
11024
11037
|
}
|
|
11025
11038
|
if (update) {
|
|
11026
|
-
|
|
11039
|
+
throw new Error("Cannot open and update an experiment at the same time");
|
|
11027
11040
|
}
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11041
|
+
const lazyMetadata2 = new LazyValue(async () => {
|
|
11042
|
+
await login({
|
|
11043
|
+
orgName,
|
|
11044
|
+
apiKey,
|
|
11045
|
+
appUrl
|
|
11046
|
+
});
|
|
11047
|
+
const args = {
|
|
11048
|
+
project_name: project,
|
|
11049
|
+
org_name: _state.orgName,
|
|
11050
|
+
experiment_name: experiment
|
|
11051
|
+
};
|
|
11052
|
+
const response = await _state.apiConn().post_json("api/experiment/get", args);
|
|
11053
|
+
if (response.length === 0) {
|
|
11054
|
+
throw new Error(
|
|
11055
|
+
`Experiment ${experiment} not found in project ${project}.`
|
|
11056
|
+
);
|
|
11031
11057
|
}
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
}
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
args
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
delete args["base_experiment"];
|
|
11067
|
-
} else {
|
|
11068
|
-
throw e;
|
|
11058
|
+
const info = response[0];
|
|
11059
|
+
return {
|
|
11060
|
+
id: info.id,
|
|
11061
|
+
name: info.name,
|
|
11062
|
+
fullInfo: info
|
|
11063
|
+
};
|
|
11064
|
+
});
|
|
11065
|
+
return new ReadonlyExperiment(
|
|
11066
|
+
lazyMetadata2
|
|
11067
|
+
);
|
|
11068
|
+
}
|
|
11069
|
+
const lazyMetadata = new LazyValue(
|
|
11070
|
+
async () => {
|
|
11071
|
+
await login({
|
|
11072
|
+
orgName,
|
|
11073
|
+
apiKey,
|
|
11074
|
+
appUrl
|
|
11075
|
+
});
|
|
11076
|
+
const args = {
|
|
11077
|
+
project_name: project,
|
|
11078
|
+
org_id: _state.orgId
|
|
11079
|
+
};
|
|
11080
|
+
if (experiment) {
|
|
11081
|
+
args["experiment_name"] = experiment;
|
|
11082
|
+
}
|
|
11083
|
+
if (description) {
|
|
11084
|
+
args["description"] = description;
|
|
11085
|
+
}
|
|
11086
|
+
if (update) {
|
|
11087
|
+
args["update"] = update;
|
|
11088
|
+
}
|
|
11089
|
+
let mergedGitMetadataSettings = {
|
|
11090
|
+
..._state.gitMetadataSettings || {
|
|
11091
|
+
collect: "all"
|
|
11069
11092
|
}
|
|
11093
|
+
};
|
|
11094
|
+
if (gitMetadataSettings) {
|
|
11095
|
+
mergedGitMetadataSettings = mergeGitMetadataSettings(
|
|
11096
|
+
mergedGitMetadataSettings,
|
|
11097
|
+
gitMetadataSettings
|
|
11098
|
+
);
|
|
11070
11099
|
}
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
id: response.project.id,
|
|
11075
|
-
name: response.project.name,
|
|
11076
|
-
fullInfo: response.project
|
|
11077
|
-
},
|
|
11078
|
-
experiment: {
|
|
11079
|
-
id: response.experiment.id,
|
|
11080
|
-
name: response.experiment.name,
|
|
11081
|
-
fullInfo: response.experiment
|
|
11100
|
+
const repoStatus2 = await isomorph_default.getRepoStatus(gitMetadataSettings);
|
|
11101
|
+
if (repoStatus2) {
|
|
11102
|
+
args["repo_info"] = repoStatus2;
|
|
11082
11103
|
}
|
|
11083
|
-
|
|
11084
|
-
|
|
11104
|
+
if (baseExperiment) {
|
|
11105
|
+
args["base_experiment"] = baseExperiment;
|
|
11106
|
+
} else {
|
|
11107
|
+
args["ancestor_commits"] = await isomorph_default.getPastNAncestors();
|
|
11108
|
+
}
|
|
11109
|
+
if (dataset !== void 0) {
|
|
11110
|
+
args["dataset_id"] = await dataset.id;
|
|
11111
|
+
args["dataset_version"] = await dataset.version();
|
|
11112
|
+
}
|
|
11113
|
+
if (isPublic !== void 0) {
|
|
11114
|
+
args["public"] = isPublic;
|
|
11115
|
+
}
|
|
11116
|
+
if (metadata) {
|
|
11117
|
+
args["metadata"] = metadata;
|
|
11118
|
+
}
|
|
11119
|
+
let response = null;
|
|
11120
|
+
while (true) {
|
|
11121
|
+
try {
|
|
11122
|
+
response = await _state.apiConn().post_json("api/experiment/register", args);
|
|
11123
|
+
break;
|
|
11124
|
+
} catch (e) {
|
|
11125
|
+
if (args["base_experiment"] && `${"data" in e && e.data}`.includes("base experiment")) {
|
|
11126
|
+
console.warn(
|
|
11127
|
+
`Base experiment ${args["base_experiment"]} not found.`
|
|
11128
|
+
);
|
|
11129
|
+
delete args["base_experiment"];
|
|
11130
|
+
} else {
|
|
11131
|
+
throw e;
|
|
11132
|
+
}
|
|
11133
|
+
}
|
|
11134
|
+
}
|
|
11135
|
+
return {
|
|
11136
|
+
project: {
|
|
11137
|
+
id: response.project.id,
|
|
11138
|
+
name: response.project.name,
|
|
11139
|
+
fullInfo: response.project
|
|
11140
|
+
},
|
|
11141
|
+
experiment: {
|
|
11142
|
+
id: response.experiment.id,
|
|
11143
|
+
name: response.experiment.name,
|
|
11144
|
+
fullInfo: response.experiment
|
|
11145
|
+
}
|
|
11146
|
+
};
|
|
11147
|
+
}
|
|
11148
|
+
);
|
|
11085
11149
|
const ret = new Experiment(lazyMetadata, dataset);
|
|
11086
11150
|
if (options.setCurrent ?? true) {
|
|
11087
11151
|
_state.currentExperiment = ret;
|
|
@@ -11206,15 +11270,15 @@ function validateAndSanitizeExperimentLogPartialArgs(event) {
|
|
|
11206
11270
|
}
|
|
11207
11271
|
}
|
|
11208
11272
|
function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
|
|
11209
|
-
if ("input" in event && event.input && "inputs" in event && event.inputs || !("input" in event) && !("inputs" in event)) {
|
|
11273
|
+
if ("input" in event && !isEmpty(event.input) && "inputs" in event && !isEmpty(event.inputs) || !("input" in event) && !("inputs" in event)) {
|
|
11210
11274
|
throw new Error(
|
|
11211
11275
|
"Exactly one of input or inputs (deprecated) must be specified. Prefer input."
|
|
11212
11276
|
);
|
|
11213
11277
|
}
|
|
11214
|
-
if (
|
|
11278
|
+
if (isEmpty(event.output)) {
|
|
11215
11279
|
throw new Error("output must be specified");
|
|
11216
11280
|
}
|
|
11217
|
-
if (
|
|
11281
|
+
if (isEmpty(event.scores)) {
|
|
11218
11282
|
throw new Error("scores must be specified");
|
|
11219
11283
|
}
|
|
11220
11284
|
if (hasDataset && event.datasetRecordId === void 0) {
|
|
@@ -11226,33 +11290,88 @@ function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
|
|
|
11226
11290
|
}
|
|
11227
11291
|
return event;
|
|
11228
11292
|
}
|
|
11229
|
-
var
|
|
11293
|
+
var ObjectFetcher = class {
|
|
11294
|
+
constructor(objectType, pinnedVersion) {
|
|
11295
|
+
this.objectType = objectType;
|
|
11296
|
+
this.pinnedVersion = pinnedVersion;
|
|
11297
|
+
this._fetchedData = void 0;
|
|
11298
|
+
}
|
|
11299
|
+
get id() {
|
|
11300
|
+
throw new Error("ObjectFetcher subclasses must have an 'id' attribute");
|
|
11301
|
+
}
|
|
11302
|
+
async getState() {
|
|
11303
|
+
throw new Error("ObjectFetcher subclasses must have a 'getState' method");
|
|
11304
|
+
}
|
|
11305
|
+
async *fetch() {
|
|
11306
|
+
const records = await this.fetchedData();
|
|
11307
|
+
for (const record of records) {
|
|
11308
|
+
yield record;
|
|
11309
|
+
}
|
|
11310
|
+
}
|
|
11311
|
+
[Symbol.iterator]() {
|
|
11312
|
+
return this.fetch();
|
|
11313
|
+
}
|
|
11314
|
+
async fetchedData() {
|
|
11315
|
+
if (this._fetchedData === void 0) {
|
|
11316
|
+
const state = await this.getState();
|
|
11317
|
+
const resp = await state.logConn().get(`object/${this.objectType}`, {
|
|
11318
|
+
id: await this.id,
|
|
11319
|
+
fmt: "json2",
|
|
11320
|
+
version: this.pinnedVersion
|
|
11321
|
+
});
|
|
11322
|
+
this._fetchedData = await resp.json();
|
|
11323
|
+
}
|
|
11324
|
+
return this._fetchedData || [];
|
|
11325
|
+
}
|
|
11326
|
+
clearCache() {
|
|
11327
|
+
this._fetchedData = void 0;
|
|
11328
|
+
}
|
|
11329
|
+
async version() {
|
|
11330
|
+
if (this.pinnedVersion !== void 0) {
|
|
11331
|
+
return this.pinnedVersion;
|
|
11332
|
+
} else {
|
|
11333
|
+
const fetchedData = await this.fetchedData();
|
|
11334
|
+
let maxVersion = void 0;
|
|
11335
|
+
for (const record of fetchedData) {
|
|
11336
|
+
const xactId = record[TRANSACTION_ID_FIELD];
|
|
11337
|
+
if (maxVersion === void 0 || (xactId ?? xactId > maxVersion)) {
|
|
11338
|
+
maxVersion = xactId;
|
|
11339
|
+
}
|
|
11340
|
+
}
|
|
11341
|
+
return maxVersion;
|
|
11342
|
+
}
|
|
11343
|
+
}
|
|
11344
|
+
};
|
|
11345
|
+
var Experiment = class extends ObjectFetcher {
|
|
11230
11346
|
constructor(lazyMetadata, dataset) {
|
|
11347
|
+
super("experiment", void 0);
|
|
11231
11348
|
// For type identification.
|
|
11232
11349
|
this.kind = "experiment";
|
|
11233
11350
|
this.lazyMetadata = lazyMetadata;
|
|
11234
11351
|
this.dataset = dataset;
|
|
11235
|
-
const logConn =
|
|
11352
|
+
const logConn = new LazyValue(
|
|
11353
|
+
() => this.getState().then((state) => state.logConn())
|
|
11354
|
+
);
|
|
11236
11355
|
this.bgLogger = new BackgroundLogger(logConn);
|
|
11237
11356
|
this.lastStartTime = getCurrentUnixTimestamp();
|
|
11238
11357
|
}
|
|
11239
11358
|
get id() {
|
|
11240
11359
|
return (async () => {
|
|
11241
|
-
return (await this.lazyMetadata).experiment.id;
|
|
11360
|
+
return (await this.lazyMetadata.get()).experiment.id;
|
|
11242
11361
|
})();
|
|
11243
11362
|
}
|
|
11244
11363
|
get name() {
|
|
11245
11364
|
return (async () => {
|
|
11246
|
-
return (await this.lazyMetadata).experiment.name;
|
|
11365
|
+
return (await this.lazyMetadata.get()).experiment.name;
|
|
11247
11366
|
})();
|
|
11248
11367
|
}
|
|
11249
11368
|
get project() {
|
|
11250
11369
|
return (async () => {
|
|
11251
|
-
return (await this.lazyMetadata).project;
|
|
11370
|
+
return (await this.lazyMetadata.get()).project;
|
|
11252
11371
|
})();
|
|
11253
11372
|
}
|
|
11254
11373
|
async getState() {
|
|
11255
|
-
await this.lazyMetadata;
|
|
11374
|
+
await this.lazyMetadata.get();
|
|
11256
11375
|
return _state;
|
|
11257
11376
|
}
|
|
11258
11377
|
/**
|
|
@@ -11312,12 +11431,32 @@ var Experiment = class {
|
|
|
11312
11431
|
startSpan(args) {
|
|
11313
11432
|
const { name, ...argsRest } = args ?? {};
|
|
11314
11433
|
return new SpanImpl({
|
|
11315
|
-
parentIds: this.lazyParentIds(),
|
|
11434
|
+
parentIds: new LazyValue(() => this.lazyParentIds()),
|
|
11316
11435
|
bgLogger: this.bgLogger,
|
|
11317
11436
|
name: name ?? "root",
|
|
11318
11437
|
...argsRest
|
|
11319
11438
|
});
|
|
11320
11439
|
}
|
|
11440
|
+
async fetchBaseExperiment() {
|
|
11441
|
+
const state = await this.getState();
|
|
11442
|
+
const conn = state.apiConn();
|
|
11443
|
+
try {
|
|
11444
|
+
const resp = await conn.post("/api/base_experiment/get_id", {
|
|
11445
|
+
id: await this.id
|
|
11446
|
+
});
|
|
11447
|
+
const base = await resp.json();
|
|
11448
|
+
return {
|
|
11449
|
+
id: base["base_exp_id"],
|
|
11450
|
+
name: base["base_exp_name"]
|
|
11451
|
+
};
|
|
11452
|
+
} catch (e) {
|
|
11453
|
+
if (e instanceof FailedHTTPResponse && e.status === 400) {
|
|
11454
|
+
return null;
|
|
11455
|
+
} else {
|
|
11456
|
+
throw e;
|
|
11457
|
+
}
|
|
11458
|
+
}
|
|
11459
|
+
}
|
|
11321
11460
|
/**
|
|
11322
11461
|
* Summarize the experiment, including the scores (compared to the closest reference experiment) and metadata.
|
|
11323
11462
|
*
|
|
@@ -11341,14 +11480,10 @@ var Experiment = class {
|
|
|
11341
11480
|
let comparisonExperimentName = void 0;
|
|
11342
11481
|
if (summarizeScores) {
|
|
11343
11482
|
if (comparisonExperimentId === void 0) {
|
|
11344
|
-
const
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
const base_experiments = await resp.json();
|
|
11349
|
-
if (base_experiments.length > 0) {
|
|
11350
|
-
comparisonExperimentId = base_experiments[0]["base_exp_id"];
|
|
11351
|
-
comparisonExperimentName = base_experiments[0]["base_exp_name"];
|
|
11483
|
+
const baseExperiment = await this.fetchBaseExperiment();
|
|
11484
|
+
if (baseExperiment !== null) {
|
|
11485
|
+
comparisonExperimentId = baseExperiment.id;
|
|
11486
|
+
comparisonExperimentName = baseExperiment.name;
|
|
11352
11487
|
}
|
|
11353
11488
|
}
|
|
11354
11489
|
if (comparisonExperimentId !== void 0) {
|
|
@@ -11386,7 +11521,11 @@ var Experiment = class {
|
|
|
11386
11521
|
* @param event.source (Optional) the source of the feedback. Must be one of "external" (default), "app", or "api".
|
|
11387
11522
|
*/
|
|
11388
11523
|
logFeedback(event) {
|
|
11389
|
-
logFeedbackImpl(
|
|
11524
|
+
logFeedbackImpl(
|
|
11525
|
+
this.bgLogger,
|
|
11526
|
+
new LazyValue(() => this.lazyParentIds()),
|
|
11527
|
+
event
|
|
11528
|
+
);
|
|
11390
11529
|
}
|
|
11391
11530
|
/**
|
|
11392
11531
|
* Flush any pending rows to the server.
|
|
@@ -11404,6 +11543,40 @@ var Experiment = class {
|
|
|
11404
11543
|
return this.id;
|
|
11405
11544
|
}
|
|
11406
11545
|
};
|
|
11546
|
+
var ReadonlyExperiment = class extends ObjectFetcher {
|
|
11547
|
+
constructor(lazyMetadata) {
|
|
11548
|
+
super("experiment", void 0);
|
|
11549
|
+
this.lazyMetadata = lazyMetadata;
|
|
11550
|
+
}
|
|
11551
|
+
get id() {
|
|
11552
|
+
return (async () => {
|
|
11553
|
+
return (await this.lazyMetadata.get()).id;
|
|
11554
|
+
})();
|
|
11555
|
+
}
|
|
11556
|
+
get name() {
|
|
11557
|
+
return (async () => {
|
|
11558
|
+
return (await this.lazyMetadata.get()).name;
|
|
11559
|
+
})();
|
|
11560
|
+
}
|
|
11561
|
+
async getState() {
|
|
11562
|
+
await this.lazyMetadata.get();
|
|
11563
|
+
return _state;
|
|
11564
|
+
}
|
|
11565
|
+
async *asDataset() {
|
|
11566
|
+
const records = this.fetch();
|
|
11567
|
+
for await (const record of records) {
|
|
11568
|
+
if (record.root_span_id !== record.span_id) {
|
|
11569
|
+
continue;
|
|
11570
|
+
}
|
|
11571
|
+
const { output, expected } = record;
|
|
11572
|
+
yield {
|
|
11573
|
+
input: record.input,
|
|
11574
|
+
expected: expected ?? output
|
|
11575
|
+
};
|
|
11576
|
+
}
|
|
11577
|
+
}
|
|
11578
|
+
};
|
|
11579
|
+
var executionCounter = 0;
|
|
11407
11580
|
var SpanImpl = class _SpanImpl {
|
|
11408
11581
|
// root_experiment should only be specified for a root span. parent_span
|
|
11409
11582
|
// should only be specified for non-root spans.
|
|
@@ -11429,7 +11602,11 @@ var SpanImpl = class _SpanImpl {
|
|
|
11429
11602
|
start: args.startTime ?? getCurrentUnixTimestamp()
|
|
11430
11603
|
},
|
|
11431
11604
|
context: { ...callerLocation },
|
|
11432
|
-
span_attributes: {
|
|
11605
|
+
span_attributes: {
|
|
11606
|
+
...args.spanAttributes,
|
|
11607
|
+
name,
|
|
11608
|
+
exec_counter: executionCounter++
|
|
11609
|
+
},
|
|
11433
11610
|
created: (/* @__PURE__ */ new Date()).toISOString()
|
|
11434
11611
|
};
|
|
11435
11612
|
this.parentIds = args.parentIds;
|
|
@@ -11467,18 +11644,18 @@ var SpanImpl = class _SpanImpl {
|
|
|
11467
11644
|
if (sanitizedAndInternalData.metrics?.end) {
|
|
11468
11645
|
this.loggedEndTime = sanitizedAndInternalData.metrics?.end;
|
|
11469
11646
|
}
|
|
11470
|
-
const parentIds = (async () => {
|
|
11471
|
-
const { kind, ...ids } = await this.parentIds;
|
|
11647
|
+
const parentIds = new LazyValue(async () => {
|
|
11648
|
+
const { kind, ...ids } = await this.parentIds.get();
|
|
11472
11649
|
return ids;
|
|
11473
|
-
})
|
|
11474
|
-
const record = (async () => {
|
|
11650
|
+
});
|
|
11651
|
+
const record = new LazyValue(async () => {
|
|
11475
11652
|
return {
|
|
11476
11653
|
...sanitizedAndInternalData,
|
|
11477
11654
|
...this.rowIds,
|
|
11478
|
-
...await parentIds,
|
|
11655
|
+
...await parentIds.get(),
|
|
11479
11656
|
[IS_MERGE_FIELD]: this.isMerge
|
|
11480
11657
|
};
|
|
11481
|
-
})
|
|
11658
|
+
});
|
|
11482
11659
|
this.bgLogger.log([record]);
|
|
11483
11660
|
}
|
|
11484
11661
|
logFeedback(event) {
|
|
@@ -11527,207 +11704,6 @@ var SpanImpl = class _SpanImpl {
|
|
|
11527
11704
|
return this.end(args);
|
|
11528
11705
|
}
|
|
11529
11706
|
};
|
|
11530
|
-
var Dataset = class {
|
|
11531
|
-
constructor(lazyMetadata, pinnedVersion) {
|
|
11532
|
-
this._fetchedData = void 0;
|
|
11533
|
-
this.lazyMetadata = lazyMetadata;
|
|
11534
|
-
this.pinnedVersion = pinnedVersion;
|
|
11535
|
-
const logConn = this.getState().then((state) => state.logConn());
|
|
11536
|
-
this.bgLogger = new BackgroundLogger(logConn);
|
|
11537
|
-
}
|
|
11538
|
-
get id() {
|
|
11539
|
-
return (async () => {
|
|
11540
|
-
return (await this.lazyMetadata).dataset.id;
|
|
11541
|
-
})();
|
|
11542
|
-
}
|
|
11543
|
-
get name() {
|
|
11544
|
-
return (async () => {
|
|
11545
|
-
return (await this.lazyMetadata).dataset.name;
|
|
11546
|
-
})();
|
|
11547
|
-
}
|
|
11548
|
-
get project() {
|
|
11549
|
-
return (async () => {
|
|
11550
|
-
return (await this.lazyMetadata).project;
|
|
11551
|
-
})();
|
|
11552
|
-
}
|
|
11553
|
-
async getState() {
|
|
11554
|
-
await this.lazyMetadata;
|
|
11555
|
-
return _state;
|
|
11556
|
-
}
|
|
11557
|
-
/**
|
|
11558
|
-
* Insert a single record to the dataset. The record will be batched and uploaded behind the scenes. If you pass in an `id`,
|
|
11559
|
-
* and a record with that `id` already exists, it will be overwritten (upsert).
|
|
11560
|
-
*
|
|
11561
|
-
* @param event The event to log.
|
|
11562
|
-
* @param event.input The argument that uniquely define an input case (an arbitrary, JSON serializable object).
|
|
11563
|
-
* @param event.output The output of your application, including post-processing (an arbitrary, JSON serializable object).
|
|
11564
|
-
* @param event.metadata (Optional) a dictionary with additional data about the test example, model outputs, or just
|
|
11565
|
-
* about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
|
|
11566
|
-
* `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
|
|
11567
|
-
* JSON-serializable type, but its keys must be strings.
|
|
11568
|
-
* @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
|
|
11569
|
-
* @returns The `id` of the logged record.
|
|
11570
|
-
*/
|
|
11571
|
-
insert({
|
|
11572
|
-
input,
|
|
11573
|
-
output,
|
|
11574
|
-
metadata,
|
|
11575
|
-
id
|
|
11576
|
-
}) {
|
|
11577
|
-
if (metadata !== void 0) {
|
|
11578
|
-
for (const key of Object.keys(metadata)) {
|
|
11579
|
-
if (typeof key !== "string") {
|
|
11580
|
-
throw new Error("metadata keys must be strings");
|
|
11581
|
-
}
|
|
11582
|
-
}
|
|
11583
|
-
}
|
|
11584
|
-
const rowId = id || v4_default();
|
|
11585
|
-
const args = (async () => ({
|
|
11586
|
-
id: rowId,
|
|
11587
|
-
inputs: input,
|
|
11588
|
-
output,
|
|
11589
|
-
project_id: (await this.project).id,
|
|
11590
|
-
dataset_id: await this.id,
|
|
11591
|
-
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11592
|
-
metadata
|
|
11593
|
-
}))();
|
|
11594
|
-
this.bgLogger.log([args]);
|
|
11595
|
-
return rowId;
|
|
11596
|
-
}
|
|
11597
|
-
delete(id) {
|
|
11598
|
-
const args = (async () => ({
|
|
11599
|
-
id,
|
|
11600
|
-
project_id: (await this.project).id,
|
|
11601
|
-
dataset_id: await this.id,
|
|
11602
|
-
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11603
|
-
_object_delete: true
|
|
11604
|
-
}))();
|
|
11605
|
-
this.bgLogger.log([args]);
|
|
11606
|
-
return id;
|
|
11607
|
-
}
|
|
11608
|
-
/**
|
|
11609
|
-
* Summarize the dataset, including high level metrics about its size and other metadata.
|
|
11610
|
-
* @param summarizeData Whether to summarize the data. If false, only the metadata will be returned.
|
|
11611
|
-
* @returns `DatasetSummary`
|
|
11612
|
-
* @returns A summary of the dataset.
|
|
11613
|
-
*/
|
|
11614
|
-
async summarize(options = {}) {
|
|
11615
|
-
let { summarizeData = true } = options || {};
|
|
11616
|
-
await this.bgLogger.flush();
|
|
11617
|
-
const state = await this.getState();
|
|
11618
|
-
const projectUrl = `${state.appUrl}/app/${encodeURIComponent(
|
|
11619
|
-
state.orgName
|
|
11620
|
-
)}/p/${encodeURIComponent((await this.project).name)}`;
|
|
11621
|
-
const datasetUrl = `${projectUrl}/d/${encodeURIComponent(await this.name)}`;
|
|
11622
|
-
let dataSummary = void 0;
|
|
11623
|
-
if (summarizeData) {
|
|
11624
|
-
dataSummary = await state.logConn().get_json(
|
|
11625
|
-
"dataset-summary",
|
|
11626
|
-
{
|
|
11627
|
-
dataset_id: await this.id
|
|
11628
|
-
},
|
|
11629
|
-
3
|
|
11630
|
-
);
|
|
11631
|
-
}
|
|
11632
|
-
return {
|
|
11633
|
-
projectName: (await this.project).name,
|
|
11634
|
-
datasetName: await this.name,
|
|
11635
|
-
projectUrl,
|
|
11636
|
-
datasetUrl,
|
|
11637
|
-
dataSummary
|
|
11638
|
-
};
|
|
11639
|
-
}
|
|
11640
|
-
/**
|
|
11641
|
-
* Fetch all records in the dataset.
|
|
11642
|
-
*
|
|
11643
|
-
* @example
|
|
11644
|
-
* ```
|
|
11645
|
-
* // Use an async iterator to fetch all records in the dataset.
|
|
11646
|
-
* for await (const record of dataset.fetch()) {
|
|
11647
|
-
* console.log(record);
|
|
11648
|
-
* }
|
|
11649
|
-
*
|
|
11650
|
-
* // You can also iterate over the dataset directly.
|
|
11651
|
-
* for await (const record of dataset) {
|
|
11652
|
-
* console.log(record);
|
|
11653
|
-
* }
|
|
11654
|
-
* ```
|
|
11655
|
-
*
|
|
11656
|
-
* @returns An iterator over the dataset's records.
|
|
11657
|
-
*/
|
|
11658
|
-
async *fetch() {
|
|
11659
|
-
const records = await this.fetchedData();
|
|
11660
|
-
for (const record of records) {
|
|
11661
|
-
yield {
|
|
11662
|
-
id: record.id,
|
|
11663
|
-
input: record.input && JSON.parse(record.input),
|
|
11664
|
-
output: record.input && JSON.parse(record.output),
|
|
11665
|
-
metadata: record.metadata && JSON.parse(record.metadata)
|
|
11666
|
-
};
|
|
11667
|
-
}
|
|
11668
|
-
this.clearCache();
|
|
11669
|
-
}
|
|
11670
|
-
/**
|
|
11671
|
-
* Fetch all records in the dataset.
|
|
11672
|
-
*
|
|
11673
|
-
* @example
|
|
11674
|
-
* ```
|
|
11675
|
-
* // Use an async iterator to fetch all records in the dataset.
|
|
11676
|
-
* for await (const record of dataset) {
|
|
11677
|
-
* console.log(record);
|
|
11678
|
-
* }
|
|
11679
|
-
* ```
|
|
11680
|
-
*/
|
|
11681
|
-
[Symbol.asyncIterator]() {
|
|
11682
|
-
return this.fetch();
|
|
11683
|
-
}
|
|
11684
|
-
async fetchedData() {
|
|
11685
|
-
if (this._fetchedData === void 0) {
|
|
11686
|
-
const state = await this.getState();
|
|
11687
|
-
const resp = await state.logConn().get("object/dataset", {
|
|
11688
|
-
id: await this.id,
|
|
11689
|
-
fmt: "json",
|
|
11690
|
-
version: this.pinnedVersion
|
|
11691
|
-
});
|
|
11692
|
-
const text = await resp.text();
|
|
11693
|
-
this._fetchedData = text.split("\n").filter((x) => x.trim() !== "").map((x) => JSON.parse(x));
|
|
11694
|
-
}
|
|
11695
|
-
return this._fetchedData || [];
|
|
11696
|
-
}
|
|
11697
|
-
clearCache() {
|
|
11698
|
-
this._fetchedData = void 0;
|
|
11699
|
-
}
|
|
11700
|
-
async version() {
|
|
11701
|
-
if (this.pinnedVersion !== void 0) {
|
|
11702
|
-
return this.pinnedVersion;
|
|
11703
|
-
} else {
|
|
11704
|
-
const fetchedData = await this.fetchedData();
|
|
11705
|
-
let maxVersion = void 0;
|
|
11706
|
-
for (const record of fetchedData) {
|
|
11707
|
-
const xactId = record[TRANSACTION_ID_FIELD];
|
|
11708
|
-
if (maxVersion === void 0 || (xactId ?? xactId > maxVersion)) {
|
|
11709
|
-
maxVersion = xactId;
|
|
11710
|
-
}
|
|
11711
|
-
}
|
|
11712
|
-
return maxVersion;
|
|
11713
|
-
}
|
|
11714
|
-
}
|
|
11715
|
-
/**
|
|
11716
|
-
* Flush any pending rows to the server.
|
|
11717
|
-
*/
|
|
11718
|
-
async flush() {
|
|
11719
|
-
return await this.bgLogger.flush();
|
|
11720
|
-
}
|
|
11721
|
-
/**
|
|
11722
|
-
* This function is deprecated. You can simply remove it from your code.
|
|
11723
|
-
*/
|
|
11724
|
-
async close() {
|
|
11725
|
-
console.warn(
|
|
11726
|
-
"close is deprecated and will be removed in a future version of braintrust. It is now a no-op and can be removed"
|
|
11727
|
-
);
|
|
11728
|
-
return this.id;
|
|
11729
|
-
}
|
|
11730
|
-
};
|
|
11731
11707
|
|
|
11732
11708
|
// src/progress.ts
|
|
11733
11709
|
var cliProgress = __toESM(require_cli_progress());
|
|
@@ -11844,6 +11820,12 @@ var GlobalPaths = findGlobalPaths();
|
|
|
11844
11820
|
// src/framework.ts
|
|
11845
11821
|
var import_chalk = __toESM(require_source());
|
|
11846
11822
|
var import_pluralize = __toESM(require_pluralize());
|
|
11823
|
+
function initExperiment(projectName, options = {}) {
|
|
11824
|
+
return init(projectName, {
|
|
11825
|
+
...options,
|
|
11826
|
+
setCurrent: false
|
|
11827
|
+
});
|
|
11828
|
+
}
|
|
11847
11829
|
globalThis._evals = {};
|
|
11848
11830
|
function serializeJSONWithPlainString(v) {
|
|
11849
11831
|
if (typeof v === "string") {
|
|
@@ -11890,10 +11872,37 @@ async function runEvaluator(experiment, evaluator, progressReporter, filters) {
|
|
|
11890
11872
|
if (typeof evaluator.data === "string") {
|
|
11891
11873
|
throw new Error("Unimplemented: string data paths");
|
|
11892
11874
|
}
|
|
11893
|
-
|
|
11894
|
-
|
|
11875
|
+
let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
|
|
11876
|
+
if ("_type" in dataResult) {
|
|
11877
|
+
if (dataResult._type !== "BaseExperiment") {
|
|
11878
|
+
throw new Error("Invalid _type");
|
|
11879
|
+
}
|
|
11880
|
+
if (!experiment) {
|
|
11881
|
+
throw new Error(
|
|
11882
|
+
"Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
|
|
11883
|
+
);
|
|
11884
|
+
}
|
|
11885
|
+
let name = dataResult.name;
|
|
11886
|
+
if (isEmpty(name)) {
|
|
11887
|
+
const baseExperiment = await experiment.fetchBaseExperiment();
|
|
11888
|
+
if (!baseExperiment) {
|
|
11889
|
+
throw new Error("BaseExperiment() failed to fetch base experiment");
|
|
11890
|
+
}
|
|
11891
|
+
name = baseExperiment.name;
|
|
11892
|
+
}
|
|
11893
|
+
dataResult = initExperiment(evaluator.projectName, {
|
|
11894
|
+
experiment: name,
|
|
11895
|
+
open: true
|
|
11896
|
+
}).asDataset();
|
|
11897
|
+
}
|
|
11898
|
+
let data = [];
|
|
11895
11899
|
if (dataResult instanceof Promise) {
|
|
11896
11900
|
data = await dataResult;
|
|
11901
|
+
} else if (Symbol.asyncIterator in dataResult) {
|
|
11902
|
+
data = [];
|
|
11903
|
+
for await (const d of dataResult) {
|
|
11904
|
+
data.push(d);
|
|
11905
|
+
}
|
|
11897
11906
|
} else {
|
|
11898
11907
|
data = dataResult;
|
|
11899
11908
|
}
|
|
@@ -16054,7 +16063,9 @@ async function getBaseBranchAncestor(remote = void 0) {
|
|
|
16054
16063
|
if (git === null) {
|
|
16055
16064
|
throw new Error("Not in a git repo");
|
|
16056
16065
|
}
|
|
16057
|
-
const { remote: remoteName, branch: baseBranch } = await getBaseBranch(
|
|
16066
|
+
const { remote: remoteName, branch: baseBranch } = await getBaseBranch(
|
|
16067
|
+
remote
|
|
16068
|
+
);
|
|
16058
16069
|
const isDirty = (await git.diffSummary()).files.length > 0;
|
|
16059
16070
|
const head = isDirty ? "HEAD" : "HEAD^";
|
|
16060
16071
|
try {
|
|
@@ -16474,7 +16485,7 @@ async function collectFiles(inputPath) {
|
|
|
16474
16485
|
files.push(inputPath);
|
|
16475
16486
|
}
|
|
16476
16487
|
} else {
|
|
16477
|
-
const walked = await
|
|
16488
|
+
const walked = await import_util3.default.promisify(fsWalk.walk)(inputPath, {
|
|
16478
16489
|
deepFilter: (entry) => {
|
|
16479
16490
|
return checkMatch(entry.path, null, EXCLUDE);
|
|
16480
16491
|
},
|