braintrust 0.0.109 → 0.0.110
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 +236 -87
- package/dist/cli.js +233 -86
- package/dist/index.js +235 -86
- package/dist/logger.d.ts +6 -17
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/browser.js
CHANGED
|
@@ -95,28 +95,77 @@ function mergeDicts(mergeInto, mergeFrom) {
|
|
|
95
95
|
function constructJsonArray(items) {
|
|
96
96
|
return `[${items.join(",")}]`;
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
98
|
+
function mapAt(m, k) {
|
|
99
|
+
const ret = m.get(k);
|
|
100
|
+
if (ret === void 0) {
|
|
101
|
+
throw new Error(`Map does not contain key ${k}`);
|
|
102
|
+
}
|
|
103
|
+
return ret;
|
|
104
|
+
}
|
|
105
|
+
function depthFirstSearch(args) {
|
|
106
|
+
var _a;
|
|
107
|
+
const { graph, firstVisitF, lastVisitF } = args;
|
|
108
|
+
for (const vs of graph.values()) {
|
|
109
|
+
for (const v of vs.values()) {
|
|
110
|
+
if (!graph.has(v)) {
|
|
111
|
+
throw new Error(`Outgoing vertex ${v} must be a key in the graph`);
|
|
108
112
|
}
|
|
109
|
-
const itemS = JSON.stringify(item);
|
|
110
|
-
items.push(itemS);
|
|
111
|
-
itemsLen += itemS.length;
|
|
112
113
|
}
|
|
113
|
-
if (items.length === 0) {
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
yield items;
|
|
117
114
|
}
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
const firstVisitedVertices = /* @__PURE__ */ new Set();
|
|
116
|
+
const visitationOrder = (_a = args.visitationOrder) != null ? _a : [...graph.keys()];
|
|
117
|
+
const events = visitationOrder.map((vertex) => ({ eventType: "first", vertex, extras: {} })).reverse();
|
|
118
|
+
while (events.length) {
|
|
119
|
+
const { eventType, vertex, extras } = events.pop();
|
|
120
|
+
if (eventType === "last") {
|
|
121
|
+
lastVisitF == null ? void 0 : lastVisitF(vertex);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (firstVisitedVertices.has(vertex)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
firstVisitedVertices.add(vertex);
|
|
128
|
+
firstVisitF == null ? void 0 : firstVisitF(vertex, { parentVertex: extras.parentVertex });
|
|
129
|
+
events.push({ eventType: "last", vertex, extras: {} });
|
|
130
|
+
mapAt(graph, vertex).forEach((child) => {
|
|
131
|
+
events.push({
|
|
132
|
+
eventType: "first",
|
|
133
|
+
vertex: child,
|
|
134
|
+
extras: { parentVertex: vertex }
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function undirectedConnectedComponents(graph) {
|
|
140
|
+
const directedGraph = new Map(
|
|
141
|
+
[...graph.vertices].map((v) => [v, /* @__PURE__ */ new Set()])
|
|
142
|
+
);
|
|
143
|
+
for (const [i, j] of graph.edges) {
|
|
144
|
+
mapAt(directedGraph, i).add(j);
|
|
145
|
+
mapAt(directedGraph, j).add(i);
|
|
146
|
+
}
|
|
147
|
+
let labelCounter = 0;
|
|
148
|
+
const vertexLabels = /* @__PURE__ */ new Map();
|
|
149
|
+
const firstVisitF = (vertex, args) => {
|
|
150
|
+
const label = (args == null ? void 0 : args.parentVertex) !== void 0 ? mapAt(vertexLabels, args == null ? void 0 : args.parentVertex) : labelCounter++;
|
|
151
|
+
vertexLabels.set(vertex, label);
|
|
152
|
+
};
|
|
153
|
+
depthFirstSearch({ graph: directedGraph, firstVisitF });
|
|
154
|
+
const output = Array.from({ length: labelCounter }).map(() => []);
|
|
155
|
+
for (const [vertex, label] of vertexLabels.entries()) {
|
|
156
|
+
output[label].push(vertex);
|
|
157
|
+
}
|
|
158
|
+
return output;
|
|
159
|
+
}
|
|
160
|
+
function topologicalSort(graph, visitationOrder) {
|
|
161
|
+
const reverseOrdering = [];
|
|
162
|
+
const lastVisitF = (vertex) => {
|
|
163
|
+
reverseOrdering.push(vertex);
|
|
164
|
+
};
|
|
165
|
+
depthFirstSearch({ graph, lastVisitF, visitationOrder });
|
|
166
|
+
return reverseOrdering.reverse();
|
|
167
|
+
}
|
|
168
|
+
function generateMergedRowKey(row, useParentIdForId) {
|
|
120
169
|
return JSON.stringify(
|
|
121
170
|
[
|
|
122
171
|
"org_id",
|
|
@@ -125,24 +174,22 @@ function generateMergedRowKey(row) {
|
|
|
125
174
|
"dataset_id",
|
|
126
175
|
"prompt_session_id",
|
|
127
176
|
"log_id",
|
|
128
|
-
"id"
|
|
177
|
+
(useParentIdForId != null ? useParentIdForId : false) ? PARENT_ID_FIELD : "id"
|
|
129
178
|
].map((k) => row[k])
|
|
130
179
|
);
|
|
131
180
|
}
|
|
132
181
|
function mergeRowBatch(rows) {
|
|
133
|
-
const out = [];
|
|
134
|
-
const remainingRows = [];
|
|
135
182
|
for (const row of rows) {
|
|
136
183
|
if (row.id === void 0) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
184
|
+
throw new Error(
|
|
185
|
+
"Logged row is missing an id. This is an internal braintrust error. Please contact us at info@braintrustdata.com for help"
|
|
186
|
+
);
|
|
140
187
|
}
|
|
141
188
|
}
|
|
142
|
-
const rowGroups =
|
|
143
|
-
for (const row of
|
|
189
|
+
const rowGroups = /* @__PURE__ */ new Map();
|
|
190
|
+
for (const row of rows) {
|
|
144
191
|
const key = generateMergedRowKey(row);
|
|
145
|
-
const existingRow = rowGroups
|
|
192
|
+
const existingRow = rowGroups.get(key);
|
|
146
193
|
if (existingRow !== void 0 && row[IS_MERGE_FIELD]) {
|
|
147
194
|
const preserveNoMerge = !existingRow[IS_MERGE_FIELD];
|
|
148
195
|
mergeDicts(existingRow, row);
|
|
@@ -150,11 +197,102 @@ function mergeRowBatch(rows) {
|
|
|
150
197
|
delete existingRow[IS_MERGE_FIELD];
|
|
151
198
|
}
|
|
152
199
|
} else {
|
|
153
|
-
rowGroups
|
|
200
|
+
rowGroups.set(key, row);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const merged = [...rowGroups.values()];
|
|
204
|
+
const rowToLabel = new Map(
|
|
205
|
+
merged.map((r, i) => [generateMergedRowKey(r), i])
|
|
206
|
+
);
|
|
207
|
+
const graph = new Map(
|
|
208
|
+
Array.from({ length: merged.length }).map((_, i) => [i, /* @__PURE__ */ new Set()])
|
|
209
|
+
);
|
|
210
|
+
merged.forEach((r, i) => {
|
|
211
|
+
const parentId = r[PARENT_ID_FIELD];
|
|
212
|
+
if (!parentId) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const parentRowKey = generateMergedRowKey(
|
|
216
|
+
r,
|
|
217
|
+
true
|
|
218
|
+
/* useParentIdForId */
|
|
219
|
+
);
|
|
220
|
+
const parentLabel = rowToLabel.get(parentRowKey);
|
|
221
|
+
if (parentLabel !== void 0) {
|
|
222
|
+
mapAt(graph, parentLabel).add(i);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
const connectedComponents = undirectedConnectedComponents({
|
|
226
|
+
vertices: new Set(graph.keys()),
|
|
227
|
+
edges: new Set(
|
|
228
|
+
[...graph.entries()].flatMap(
|
|
229
|
+
([k, vs]) => [...vs].map((v) => {
|
|
230
|
+
const ret = [k, v];
|
|
231
|
+
return ret;
|
|
232
|
+
})
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
});
|
|
236
|
+
const buckets = connectedComponents.map(
|
|
237
|
+
(cc) => topologicalSort(
|
|
238
|
+
graph,
|
|
239
|
+
cc
|
|
240
|
+
/* visitationOrder */
|
|
241
|
+
)
|
|
242
|
+
);
|
|
243
|
+
return buckets.map((bucket) => bucket.map((i) => merged[i]));
|
|
244
|
+
}
|
|
245
|
+
function batchItems(args) {
|
|
246
|
+
var _a, _b;
|
|
247
|
+
let { items } = args;
|
|
248
|
+
const batchMaxNumItems = (_a = args.batchMaxNumItems) != null ? _a : Number.POSITIVE_INFINITY;
|
|
249
|
+
const batchMaxNumBytes = (_b = args.batchMaxNumBytes) != null ? _b : Number.POSITIVE_INFINITY;
|
|
250
|
+
const output = [];
|
|
251
|
+
let nextItems = [];
|
|
252
|
+
let batchSet = [];
|
|
253
|
+
let batch = [];
|
|
254
|
+
let batchLen = 0;
|
|
255
|
+
function addToBatch(item) {
|
|
256
|
+
batch.push(item);
|
|
257
|
+
batchLen += item.length;
|
|
258
|
+
}
|
|
259
|
+
function flushBatch() {
|
|
260
|
+
batchSet.push(batch);
|
|
261
|
+
batch = [];
|
|
262
|
+
batchLen = 0;
|
|
263
|
+
}
|
|
264
|
+
while (items.length) {
|
|
265
|
+
for (const bucket of items) {
|
|
266
|
+
let i = 0;
|
|
267
|
+
for (const item of bucket) {
|
|
268
|
+
if (batch.length === 0 || item.length + batchLen < batchMaxNumBytes && batch.length < batchMaxNumItems) {
|
|
269
|
+
addToBatch(item);
|
|
270
|
+
} else if (i === 0) {
|
|
271
|
+
flushBatch();
|
|
272
|
+
addToBatch(item);
|
|
273
|
+
} else {
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
++i;
|
|
277
|
+
}
|
|
278
|
+
if (i < bucket.length) {
|
|
279
|
+
nextItems.push(bucket.slice(i));
|
|
280
|
+
}
|
|
281
|
+
if (batchLen >= batchMaxNumBytes || batch.length > batchMaxNumItems) {
|
|
282
|
+
flushBatch();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (batch.length) {
|
|
286
|
+
flushBatch();
|
|
154
287
|
}
|
|
288
|
+
if (batchSet.length) {
|
|
289
|
+
output.push(batchSet);
|
|
290
|
+
batchSet = [];
|
|
291
|
+
}
|
|
292
|
+
items = nextItems;
|
|
293
|
+
nextItems = [];
|
|
155
294
|
}
|
|
156
|
-
|
|
157
|
-
return out;
|
|
295
|
+
return output;
|
|
158
296
|
}
|
|
159
297
|
var DEFAULT_IS_LEGACY_DATASET = true;
|
|
160
298
|
function ensureDatasetRecord(r, legacy) {
|
|
@@ -277,13 +415,9 @@ var LazyValue = class {
|
|
|
277
415
|
// src/logger.ts
|
|
278
416
|
var NoopSpan = class {
|
|
279
417
|
id;
|
|
280
|
-
span_id;
|
|
281
|
-
root_span_id;
|
|
282
418
|
kind = "span";
|
|
283
419
|
constructor() {
|
|
284
420
|
this.id = "";
|
|
285
|
-
this.span_id = "";
|
|
286
|
-
this.root_span_id = "";
|
|
287
421
|
}
|
|
288
422
|
log(_) {
|
|
289
423
|
}
|
|
@@ -761,14 +895,17 @@ var BackgroundLogger = class {
|
|
|
761
895
|
if (allItems.length === 0) {
|
|
762
896
|
return;
|
|
763
897
|
}
|
|
764
|
-
const
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
898
|
+
const allItemsStr = allItems.map(
|
|
899
|
+
(bucket) => bucket.map((item) => JSON.stringify(item))
|
|
900
|
+
);
|
|
901
|
+
const batchSets = batchItems({
|
|
902
|
+
items: allItemsStr,
|
|
903
|
+
batchMaxNumItems: batchSize,
|
|
904
|
+
batchMaxNumBytes: this.maxRequestSize / 2
|
|
905
|
+
});
|
|
906
|
+
for (const batchSet of batchSets) {
|
|
907
|
+
const postPromises = batchSet.map(
|
|
908
|
+
(batch) => (async () => {
|
|
772
909
|
try {
|
|
773
910
|
await this.submitLogsRequest(batch);
|
|
774
911
|
return { type: "success" };
|
|
@@ -777,14 +914,14 @@ var BackgroundLogger = class {
|
|
|
777
914
|
}
|
|
778
915
|
})()
|
|
779
916
|
);
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
917
|
+
const results = await Promise.all(postPromises);
|
|
918
|
+
const failingResultErrors = results.map((r) => r.type === "success" ? void 0 : r.value).filter((r) => r !== void 0);
|
|
919
|
+
if (failingResultErrors.length) {
|
|
920
|
+
throw new AggregateError(
|
|
921
|
+
failingResultErrors,
|
|
922
|
+
`Encountered the following errors while logging:`
|
|
923
|
+
);
|
|
924
|
+
}
|
|
788
925
|
}
|
|
789
926
|
if (this.items.length > 0) {
|
|
790
927
|
await this.flushOnce(args);
|
|
@@ -1817,16 +1954,24 @@ var SpanImpl = class _SpanImpl {
|
|
|
1817
1954
|
this.parentObject = args.parentObject;
|
|
1818
1955
|
this.parentIds = args.parentIds;
|
|
1819
1956
|
const id = args.event?.id ?? v4_default();
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
this.rowIds[PARENT_ID_FIELD] =
|
|
1957
|
+
this.rowIds = { id };
|
|
1958
|
+
const parentSpanInfo = "parentSpanInfo" in args ? args.parentSpanInfo : void 0;
|
|
1959
|
+
const parentId = "parentId" in args ? args.parentId : void 0;
|
|
1960
|
+
if (parentSpanInfo && parentId) {
|
|
1961
|
+
throw new Error(
|
|
1962
|
+
"Only one of parentSpanInfo and parentId may be specified"
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
if (parentId) {
|
|
1966
|
+
this.rowIds[PARENT_ID_FIELD] = parentId;
|
|
1967
|
+
} else {
|
|
1968
|
+
this.rowIds.span_id = v4_default();
|
|
1969
|
+
if (parentSpanInfo) {
|
|
1970
|
+
this.rowIds.root_span_id = parentSpanInfo.root_span_id;
|
|
1971
|
+
this.internalData.span_parents = [parentSpanInfo.span_id];
|
|
1972
|
+
} else {
|
|
1973
|
+
this.rowIds.root_span_id = this.rowIds.span_id;
|
|
1974
|
+
}
|
|
1830
1975
|
}
|
|
1831
1976
|
this.isMerge = false;
|
|
1832
1977
|
const { id: _id, ...eventRest } = args.event ?? {};
|
|
@@ -1836,37 +1981,29 @@ var SpanImpl = class _SpanImpl {
|
|
|
1836
1981
|
get id() {
|
|
1837
1982
|
return this.rowIds.id;
|
|
1838
1983
|
}
|
|
1839
|
-
get span_id() {
|
|
1840
|
-
return this.rowIds.span_id;
|
|
1841
|
-
}
|
|
1842
|
-
get root_span_id() {
|
|
1843
|
-
return this.rowIds.root_span_id;
|
|
1844
|
-
}
|
|
1845
1984
|
log(event) {
|
|
1846
1985
|
const sanitized = validateAndSanitizeExperimentLogPartialArgs(event);
|
|
1847
1986
|
let sanitizedAndInternalData = { ...this.internalData };
|
|
1848
1987
|
mergeDicts(sanitizedAndInternalData, sanitized);
|
|
1849
1988
|
this.internalData = {};
|
|
1850
|
-
if (sanitizedAndInternalData.metrics?.end) {
|
|
1851
|
-
this.loggedEndTime = sanitizedAndInternalData.metrics?.end;
|
|
1852
|
-
}
|
|
1853
|
-
const parentIds = new LazyValue(async () => {
|
|
1854
|
-
const { kind, ...ids } = await this.parentIds.get();
|
|
1855
|
-
return ids;
|
|
1856
|
-
});
|
|
1857
1989
|
if (sanitizedAndInternalData.tags && sanitizedAndInternalData.tags.length > 0 && this.rowIds.span_id !== this.rowIds.root_span_id) {
|
|
1858
1990
|
throw new Error("Tags can only be logged to the root span");
|
|
1859
1991
|
}
|
|
1860
|
-
|
|
1861
|
-
sanitizedAndInternalData
|
|
1862
|
-
|
|
1863
|
-
|
|
1992
|
+
let partialRecord = {
|
|
1993
|
+
...sanitizedAndInternalData,
|
|
1994
|
+
...this.rowIds,
|
|
1995
|
+
[IS_MERGE_FIELD]: this.isMerge
|
|
1996
|
+
};
|
|
1997
|
+
if (partialRecord.metrics?.end) {
|
|
1998
|
+
this.loggedEndTime = partialRecord.metrics?.end;
|
|
1999
|
+
}
|
|
2000
|
+
const serializedPartialRecord = JSON.stringify(partialRecord);
|
|
2001
|
+
partialRecord = JSON.parse(serializedPartialRecord);
|
|
1864
2002
|
const record = new LazyValue(async () => {
|
|
2003
|
+
const { kind, ...parentIds } = await this.parentIds.get();
|
|
1865
2004
|
return {
|
|
1866
|
-
...
|
|
1867
|
-
...
|
|
1868
|
-
...await parentIds.get(),
|
|
1869
|
-
[IS_MERGE_FIELD]: this.isMerge
|
|
2005
|
+
...partialRecord,
|
|
2006
|
+
...parentIds
|
|
1870
2007
|
};
|
|
1871
2008
|
});
|
|
1872
2009
|
this.bgLogger.log([record]);
|
|
@@ -1892,14 +2029,24 @@ var SpanImpl = class _SpanImpl {
|
|
|
1892
2029
|
);
|
|
1893
2030
|
}
|
|
1894
2031
|
startSpan(args) {
|
|
2032
|
+
const parentId = args?.parentId ?? (this.rowIds[PARENT_ID_FIELD] ? this.id : void 0);
|
|
2033
|
+
const parentSpanInfo = (() => {
|
|
2034
|
+
if (parentId)
|
|
2035
|
+
return void 0;
|
|
2036
|
+
if (!(this.rowIds.span_id && this.rowIds.root_span_id)) {
|
|
2037
|
+
throw new Error("Impossible");
|
|
2038
|
+
}
|
|
2039
|
+
return {
|
|
2040
|
+
span_id: this.rowIds.span_id,
|
|
2041
|
+
root_span_id: this.rowIds.root_span_id
|
|
2042
|
+
};
|
|
2043
|
+
})();
|
|
1895
2044
|
return new _SpanImpl({
|
|
1896
2045
|
parentObject: this.parentObject,
|
|
1897
2046
|
parentIds: this.parentIds,
|
|
1898
2047
|
bgLogger: this.bgLogger,
|
|
1899
|
-
parentSpanInfo
|
|
1900
|
-
|
|
1901
|
-
root_span_id: this.rowIds.root_span_id
|
|
1902
|
-
},
|
|
2048
|
+
parentSpanInfo,
|
|
2049
|
+
parentId,
|
|
1903
2050
|
...args
|
|
1904
2051
|
});
|
|
1905
2052
|
}
|
|
@@ -2226,7 +2373,9 @@ function wrapChatCompletion(completion) {
|
|
|
2226
2373
|
if (params.stream) {
|
|
2227
2374
|
const startTime = getCurrentUnixTimestamp();
|
|
2228
2375
|
const ret = await completion(params, options);
|
|
2229
|
-
|
|
2376
|
+
const wrapperStream = new WrapperStream(span, startTime, ret.iterator());
|
|
2377
|
+
ret.iterator = () => wrapperStream[Symbol.asyncIterator]();
|
|
2378
|
+
return ret;
|
|
2230
2379
|
} else {
|
|
2231
2380
|
try {
|
|
2232
2381
|
const ret = await completion(
|