braintrust 0.0.89 → 0.0.91
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 +201 -21
- package/dist/cli.js +132 -13
- package/dist/index.js +211 -23
- package/dist/logger.d.ts +74 -6
- package/dist/oai.d.ts +5 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/util.d.ts +1 -0
- package/package.json +2 -2
package/dist/browser.js
CHANGED
|
@@ -73,6 +73,10 @@ var v4_default = v4;
|
|
|
73
73
|
// ../core/js/dist/index.mjs
|
|
74
74
|
var TRANSACTION_ID_FIELD = "_xact_id";
|
|
75
75
|
var IS_MERGE_FIELD = "_is_merge";
|
|
76
|
+
var AUDIT_SOURCE_FIELD = "_audit_source";
|
|
77
|
+
var AUDIT_METADATA_FIELD = "_audit_metadata";
|
|
78
|
+
var VALID_SOURCES = ["app", "api", "external"];
|
|
79
|
+
var PARENT_ID_FIELD = "_parent_id";
|
|
76
80
|
function mergeDicts(mergeInto, mergeFrom) {
|
|
77
81
|
for (const [k, mergeFromV] of Object.entries(mergeFrom)) {
|
|
78
82
|
const mergeIntoV = mergeInto[k];
|
|
@@ -85,6 +89,7 @@ function mergeDicts(mergeInto, mergeFrom) {
|
|
|
85
89
|
mergeInto[k] = mergeFromV;
|
|
86
90
|
}
|
|
87
91
|
}
|
|
92
|
+
return mergeInto;
|
|
88
93
|
}
|
|
89
94
|
function generateMergedRowKey(row) {
|
|
90
95
|
return JSON.stringify(
|
|
@@ -126,6 +131,15 @@ function mergeRowBatch(rows) {
|
|
|
126
131
|
out.push(...Object.values(rowGroups));
|
|
127
132
|
return out;
|
|
128
133
|
}
|
|
134
|
+
var SpanTypeAttribute = /* @__PURE__ */ ((SpanTypeAttribute2) => {
|
|
135
|
+
SpanTypeAttribute2["LLM"] = "llm";
|
|
136
|
+
SpanTypeAttribute2["SCORE"] = "score";
|
|
137
|
+
SpanTypeAttribute2["FUNCTION"] = "function";
|
|
138
|
+
SpanTypeAttribute2["EVAL"] = "eval";
|
|
139
|
+
SpanTypeAttribute2["TASK"] = "task";
|
|
140
|
+
SpanTypeAttribute2["TOOL"] = "tool";
|
|
141
|
+
return SpanTypeAttribute2;
|
|
142
|
+
})(SpanTypeAttribute || {});
|
|
129
143
|
|
|
130
144
|
// src/util.ts
|
|
131
145
|
var GLOBAL_PROJECT = "Global";
|
|
@@ -148,6 +162,9 @@ function runFinally(f, finallyF) {
|
|
|
148
162
|
function getCurrentUnixTimestamp() {
|
|
149
163
|
return (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
150
164
|
}
|
|
165
|
+
function isEmpty(a) {
|
|
166
|
+
return a === void 0 || a === null;
|
|
167
|
+
}
|
|
151
168
|
|
|
152
169
|
// src/logger.ts
|
|
153
170
|
var NoopSpan = class {
|
|
@@ -159,6 +176,8 @@ var NoopSpan = class {
|
|
|
159
176
|
}
|
|
160
177
|
log(_) {
|
|
161
178
|
}
|
|
179
|
+
logFeedback(event) {
|
|
180
|
+
}
|
|
162
181
|
traced(callback, _1) {
|
|
163
182
|
return callback(this);
|
|
164
183
|
}
|
|
@@ -333,6 +352,70 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
333
352
|
return await resp.json();
|
|
334
353
|
}
|
|
335
354
|
};
|
|
355
|
+
function logFeedbackImpl(bgLogger, parentIds, {
|
|
356
|
+
id,
|
|
357
|
+
expected,
|
|
358
|
+
scores,
|
|
359
|
+
metadata: inputMetadata,
|
|
360
|
+
comment,
|
|
361
|
+
source: inputSource
|
|
362
|
+
}) {
|
|
363
|
+
const source = inputSource ?? "external";
|
|
364
|
+
if (!VALID_SOURCES.includes(source)) {
|
|
365
|
+
throw new Error(`source must be one of ${VALID_SOURCES}`);
|
|
366
|
+
}
|
|
367
|
+
if (isEmpty(scores) && isEmpty(expected) && isEmpty(comment)) {
|
|
368
|
+
throw new Error(
|
|
369
|
+
"At least one of scores, expected, or comment must be specified"
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
const validatedEvent = validateAndSanitizeExperimentLogPartialArgs({
|
|
373
|
+
scores,
|
|
374
|
+
metadata: inputMetadata,
|
|
375
|
+
expected
|
|
376
|
+
});
|
|
377
|
+
let { metadata, ...updateEvent } = validatedEvent;
|
|
378
|
+
updateEvent = Object.fromEntries(
|
|
379
|
+
Object.entries(updateEvent).filter(([_, v]) => !isEmpty(v))
|
|
380
|
+
);
|
|
381
|
+
const trueParentIds = (async () => {
|
|
382
|
+
const { kind, ...ids } = await parentIds;
|
|
383
|
+
return ids;
|
|
384
|
+
})();
|
|
385
|
+
if (Object.keys(updateEvent).length > 0) {
|
|
386
|
+
const record = (async () => {
|
|
387
|
+
return {
|
|
388
|
+
id,
|
|
389
|
+
...updateEvent,
|
|
390
|
+
...await trueParentIds,
|
|
391
|
+
[AUDIT_SOURCE_FIELD]: source,
|
|
392
|
+
[AUDIT_METADATA_FIELD]: metadata,
|
|
393
|
+
[IS_MERGE_FIELD]: true
|
|
394
|
+
};
|
|
395
|
+
})();
|
|
396
|
+
bgLogger.log([record]);
|
|
397
|
+
}
|
|
398
|
+
if (!isEmpty(comment)) {
|
|
399
|
+
const record = (async () => {
|
|
400
|
+
return {
|
|
401
|
+
id: v4_default(),
|
|
402
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
403
|
+
origin: {
|
|
404
|
+
// NOTE: We do not know (or care?) what the transaction id of the row that
|
|
405
|
+
// we're commenting on is here, so we omit it.
|
|
406
|
+
id
|
|
407
|
+
},
|
|
408
|
+
comment: {
|
|
409
|
+
text: comment
|
|
410
|
+
},
|
|
411
|
+
...await trueParentIds,
|
|
412
|
+
[AUDIT_SOURCE_FIELD]: source,
|
|
413
|
+
[AUDIT_METADATA_FIELD]: metadata
|
|
414
|
+
};
|
|
415
|
+
})();
|
|
416
|
+
bgLogger.log([record]);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
336
419
|
var Logger = class {
|
|
337
420
|
constructor(lazyMetadata, logOptions = {}) {
|
|
338
421
|
// For type identification.
|
|
@@ -411,6 +494,14 @@ var Logger = class {
|
|
|
411
494
|
})();
|
|
412
495
|
}
|
|
413
496
|
}
|
|
497
|
+
async lazyParentIds() {
|
|
498
|
+
return {
|
|
499
|
+
kind: "project_log",
|
|
500
|
+
org_id: await this.org_id,
|
|
501
|
+
project_id: (await this.project).id,
|
|
502
|
+
log_id: "g"
|
|
503
|
+
};
|
|
504
|
+
}
|
|
414
505
|
/**
|
|
415
506
|
* Lower-level alternative to `traced`, which does not automatically end the span or mark it as current.
|
|
416
507
|
*
|
|
@@ -418,19 +509,27 @@ var Logger = class {
|
|
|
418
509
|
*/
|
|
419
510
|
startSpan(args) {
|
|
420
511
|
const { name, ...argsRest } = args ?? {};
|
|
421
|
-
const parentIds = (async () => ({
|
|
422
|
-
kind: "project_log",
|
|
423
|
-
org_id: await this.org_id,
|
|
424
|
-
project_id: (await this.project).id,
|
|
425
|
-
log_id: "g"
|
|
426
|
-
}))();
|
|
427
512
|
return new SpanImpl({
|
|
428
|
-
parentIds,
|
|
513
|
+
parentIds: this.lazyParentIds(),
|
|
429
514
|
bgLogger: this.bgLogger,
|
|
430
515
|
name: name ?? "root",
|
|
431
516
|
...argsRest
|
|
432
517
|
});
|
|
433
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Log feedback to an event. Feedback is used to save feedback scores, set an expected value, or add a comment.
|
|
521
|
+
*
|
|
522
|
+
* @param event
|
|
523
|
+
* @param event.id The id of the event to log feedback for. This is the `id` returned by `log` or accessible as the `id` field of a span.
|
|
524
|
+
* @param event.scores (Optional) a dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the existing scores for the event.
|
|
525
|
+
* @param event.expected (Optional) the ground truth value (an arbitrary, JSON serializable object) that you'd compare to `output` to determine if your `output` value is correct or not.
|
|
526
|
+
* @param event.comment (Optional) an optional comment string to log about the event.
|
|
527
|
+
* @param event.metadata (Optional) a dictionary with additional data about the feedback. If you have a `user_id`, you can log it here and access it in the Braintrust UI.
|
|
528
|
+
* @param event.source (Optional) the source of the feedback. Must be one of "external" (default), "app", or "api".
|
|
529
|
+
*/
|
|
530
|
+
logFeedback(event) {
|
|
531
|
+
logFeedbackImpl(this.bgLogger, this.lazyParentIds(), event);
|
|
532
|
+
}
|
|
434
533
|
/*
|
|
435
534
|
* Flush any pending logs to the server.
|
|
436
535
|
*/
|
|
@@ -1022,6 +1121,13 @@ var Experiment = class {
|
|
|
1022
1121
|
() => span.end()
|
|
1023
1122
|
);
|
|
1024
1123
|
}
|
|
1124
|
+
async lazyParentIds() {
|
|
1125
|
+
return {
|
|
1126
|
+
kind: "experiment",
|
|
1127
|
+
project_id: (await this.project).id,
|
|
1128
|
+
experiment_id: await this.id
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1025
1131
|
/**
|
|
1026
1132
|
* Lower-level alternative to `traced`, which does not automatically end the span or mark it as current.
|
|
1027
1133
|
*
|
|
@@ -1029,13 +1135,8 @@ var Experiment = class {
|
|
|
1029
1135
|
*/
|
|
1030
1136
|
startSpan(args) {
|
|
1031
1137
|
const { name, ...argsRest } = args ?? {};
|
|
1032
|
-
const parentIds = (async () => ({
|
|
1033
|
-
kind: "experiment",
|
|
1034
|
-
project_id: (await this.project).id,
|
|
1035
|
-
experiment_id: await this.id
|
|
1036
|
-
}))();
|
|
1037
1138
|
return new SpanImpl({
|
|
1038
|
-
parentIds,
|
|
1139
|
+
parentIds: this.lazyParentIds(),
|
|
1039
1140
|
bgLogger: this.bgLogger,
|
|
1040
1141
|
name: name ?? "root",
|
|
1041
1142
|
...argsRest
|
|
@@ -1097,6 +1198,20 @@ var Experiment = class {
|
|
|
1097
1198
|
metrics
|
|
1098
1199
|
};
|
|
1099
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Log feedback to an event in the experiment. Feedback is used to save feedback scores, set an expected value, or add a comment.
|
|
1203
|
+
*
|
|
1204
|
+
* @param event
|
|
1205
|
+
* @param event.id The id of the event to log feedback for. This is the `id` returned by `log` or accessible as the `id` field of a span.
|
|
1206
|
+
* @param event.scores (Optional) a dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the existing scores for the event.
|
|
1207
|
+
* @param event.expected (Optional) the ground truth value (an arbitrary, JSON serializable object) that you'd compare to `output` to determine if your `output` value is correct or not.
|
|
1208
|
+
* @param event.comment (Optional) an optional comment string to log about the event.
|
|
1209
|
+
* @param event.metadata (Optional) a dictionary with additional data about the feedback. If you have a `user_id`, you can log it here and access it in the Braintrust UI.
|
|
1210
|
+
* @param event.source (Optional) the source of the feedback. Must be one of "external" (default), "app", or "api".
|
|
1211
|
+
*/
|
|
1212
|
+
logFeedback(event) {
|
|
1213
|
+
logFeedbackImpl(this.bgLogger, this.lazyParentIds(), event);
|
|
1214
|
+
}
|
|
1100
1215
|
/**
|
|
1101
1216
|
* Flush any pending rows to the server.
|
|
1102
1217
|
*/
|
|
@@ -1147,10 +1262,12 @@ var SpanImpl = class _SpanImpl {
|
|
|
1147
1262
|
this.rowIds = {
|
|
1148
1263
|
id,
|
|
1149
1264
|
span_id,
|
|
1150
|
-
root_span_id: args.parentSpanInfo?.root_span_id
|
|
1265
|
+
root_span_id: "parentSpanInfo" in args && args.parentSpanInfo?.root_span_id ? args.parentSpanInfo.root_span_id : span_id
|
|
1151
1266
|
};
|
|
1152
|
-
if (args.parentSpanInfo) {
|
|
1267
|
+
if ("parentSpanInfo" in args && args.parentSpanInfo?.span_id) {
|
|
1153
1268
|
this.internalData.span_parents = [args.parentSpanInfo.span_id];
|
|
1269
|
+
} else if ("parentId" in args && !isEmpty(args.parentId)) {
|
|
1270
|
+
this.rowIds[PARENT_ID_FIELD] = args.parentId;
|
|
1154
1271
|
}
|
|
1155
1272
|
this.isMerge = false;
|
|
1156
1273
|
const { id: _id, ...eventRest } = args.event ?? {};
|
|
@@ -1174,16 +1291,26 @@ var SpanImpl = class _SpanImpl {
|
|
|
1174
1291
|
if (sanitizedAndInternalData.metrics?.end) {
|
|
1175
1292
|
this.loggedEndTime = sanitizedAndInternalData.metrics?.end;
|
|
1176
1293
|
}
|
|
1294
|
+
const parentIds = (async () => {
|
|
1295
|
+
const { kind, ...ids } = await this.parentIds;
|
|
1296
|
+
return ids;
|
|
1297
|
+
})();
|
|
1177
1298
|
const record = (async () => {
|
|
1178
1299
|
return {
|
|
1179
1300
|
...sanitizedAndInternalData,
|
|
1180
1301
|
...this.rowIds,
|
|
1181
|
-
...await
|
|
1302
|
+
...await parentIds,
|
|
1182
1303
|
[IS_MERGE_FIELD]: this.isMerge
|
|
1183
1304
|
};
|
|
1184
1305
|
})();
|
|
1185
1306
|
this.bgLogger.log([record]);
|
|
1186
1307
|
}
|
|
1308
|
+
logFeedback(event) {
|
|
1309
|
+
logFeedbackImpl(this.bgLogger, this.parentIds, {
|
|
1310
|
+
...event,
|
|
1311
|
+
id: this.id
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1187
1314
|
traced(callback, args) {
|
|
1188
1315
|
const { setCurrent, ...argsRest } = args ?? {};
|
|
1189
1316
|
const span = this.startSpan(argsRest);
|
|
@@ -1451,6 +1578,7 @@ function wrapOpenAI(openai) {
|
|
|
1451
1578
|
return openai;
|
|
1452
1579
|
}
|
|
1453
1580
|
}
|
|
1581
|
+
globalThis.__inherited_braintrust_wrap_openai = wrapOpenAI;
|
|
1454
1582
|
function wrapOpenAIv4(openai) {
|
|
1455
1583
|
let completionProxy = new Proxy(openai.chat.completions, {
|
|
1456
1584
|
get(target, name, receiver) {
|
|
@@ -1469,6 +1597,15 @@ function wrapOpenAIv4(openai) {
|
|
|
1469
1597
|
return Reflect.get(target, name, receiver);
|
|
1470
1598
|
}
|
|
1471
1599
|
});
|
|
1600
|
+
let embeddingProxy = new Proxy(openai.embeddings, {
|
|
1601
|
+
get(target, name, receiver) {
|
|
1602
|
+
const baseVal = Reflect.get(target, name, receiver);
|
|
1603
|
+
if (name === "create") {
|
|
1604
|
+
return wrapEmbeddings(baseVal.bind(target));
|
|
1605
|
+
}
|
|
1606
|
+
return baseVal;
|
|
1607
|
+
}
|
|
1608
|
+
});
|
|
1472
1609
|
let betaProxy;
|
|
1473
1610
|
if (openai.beta?.chat?.completions?.stream) {
|
|
1474
1611
|
let betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
|
|
@@ -1502,6 +1639,9 @@ function wrapOpenAIv4(openai) {
|
|
|
1502
1639
|
if (name === "chat") {
|
|
1503
1640
|
return chatProxy;
|
|
1504
1641
|
}
|
|
1642
|
+
if (name === "embeddings") {
|
|
1643
|
+
return embeddingProxy;
|
|
1644
|
+
}
|
|
1505
1645
|
if (name === "beta" && betaProxy) {
|
|
1506
1646
|
return betaProxy;
|
|
1507
1647
|
}
|
|
@@ -1511,10 +1651,13 @@ function wrapOpenAIv4(openai) {
|
|
|
1511
1651
|
return proxy;
|
|
1512
1652
|
}
|
|
1513
1653
|
function wrapBetaChatCompletion(completion) {
|
|
1514
|
-
return
|
|
1654
|
+
return (params) => {
|
|
1515
1655
|
const { messages, ...rest } = params;
|
|
1516
1656
|
const span = startSpan({
|
|
1517
1657
|
name: "OpenAI Chat Completion",
|
|
1658
|
+
spanAttributes: {
|
|
1659
|
+
type: SpanTypeAttribute.LLM
|
|
1660
|
+
},
|
|
1518
1661
|
event: {
|
|
1519
1662
|
input: messages,
|
|
1520
1663
|
metadata: {
|
|
@@ -1523,7 +1666,7 @@ function wrapBetaChatCompletion(completion) {
|
|
|
1523
1666
|
}
|
|
1524
1667
|
});
|
|
1525
1668
|
const startTime = getCurrentUnixTimestamp();
|
|
1526
|
-
const ret =
|
|
1669
|
+
const ret = completion(params);
|
|
1527
1670
|
let first = true;
|
|
1528
1671
|
ret.on("chunk", (_chunk) => {
|
|
1529
1672
|
if (first) {
|
|
@@ -1548,10 +1691,13 @@ function wrapBetaChatCompletion(completion) {
|
|
|
1548
1691
|
};
|
|
1549
1692
|
}
|
|
1550
1693
|
function wrapChatCompletion(completion) {
|
|
1551
|
-
return async (params) => {
|
|
1694
|
+
return async (params, options) => {
|
|
1552
1695
|
const { messages, ...rest } = params;
|
|
1553
1696
|
const span = startSpan({
|
|
1554
1697
|
name: "OpenAI Chat Completion",
|
|
1698
|
+
spanAttributes: {
|
|
1699
|
+
type: SpanTypeAttribute.LLM
|
|
1700
|
+
},
|
|
1555
1701
|
event: {
|
|
1556
1702
|
input: messages,
|
|
1557
1703
|
metadata: {
|
|
@@ -1561,11 +1707,14 @@ function wrapChatCompletion(completion) {
|
|
|
1561
1707
|
});
|
|
1562
1708
|
if (params.stream) {
|
|
1563
1709
|
const startTime = getCurrentUnixTimestamp();
|
|
1564
|
-
const ret = await completion(params);
|
|
1710
|
+
const ret = await completion(params, options);
|
|
1565
1711
|
return new WrapperStream(span, startTime, ret);
|
|
1566
1712
|
} else {
|
|
1567
1713
|
try {
|
|
1568
|
-
const ret = await completion(
|
|
1714
|
+
const ret = await completion(
|
|
1715
|
+
params,
|
|
1716
|
+
options
|
|
1717
|
+
);
|
|
1569
1718
|
const { messages: messages2, ...rest2 } = params;
|
|
1570
1719
|
span.log({
|
|
1571
1720
|
input: messages2,
|
|
@@ -1586,6 +1735,37 @@ function wrapChatCompletion(completion) {
|
|
|
1586
1735
|
}
|
|
1587
1736
|
};
|
|
1588
1737
|
}
|
|
1738
|
+
function wrapEmbeddings(create) {
|
|
1739
|
+
return async (params, options) => {
|
|
1740
|
+
const { input, ...rest } = params;
|
|
1741
|
+
return traced(
|
|
1742
|
+
async (span) => {
|
|
1743
|
+
const result = await create(params, options);
|
|
1744
|
+
const output = result.data[0];
|
|
1745
|
+
span.log({
|
|
1746
|
+
output,
|
|
1747
|
+
metrics: {
|
|
1748
|
+
tokens: result.usage?.total_tokens,
|
|
1749
|
+
prompt_tokens: result.usage?.prompt_tokens
|
|
1750
|
+
}
|
|
1751
|
+
});
|
|
1752
|
+
return result;
|
|
1753
|
+
},
|
|
1754
|
+
{
|
|
1755
|
+
name: "OpenAI Embedding",
|
|
1756
|
+
spanAttributes: {
|
|
1757
|
+
type: SpanTypeAttribute.LLM
|
|
1758
|
+
},
|
|
1759
|
+
event: {
|
|
1760
|
+
input,
|
|
1761
|
+
metadata: {
|
|
1762
|
+
...rest
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
);
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1589
1769
|
var WrapperStream = class {
|
|
1590
1770
|
constructor(span, startTime, iter) {
|
|
1591
1771
|
this.span = span;
|
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.91",
|
|
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.12",
|
|
9112
9112
|
argparse: "^2.0.1",
|
|
9113
9113
|
chalk: "^4.1.2",
|
|
9114
9114
|
"cli-progress": "^3.12.0",
|
|
@@ -10511,6 +10511,10 @@ var import_pluralize2 = __toESM(require_pluralize());
|
|
|
10511
10511
|
// ../core/js/dist/index.mjs
|
|
10512
10512
|
var TRANSACTION_ID_FIELD = "_xact_id";
|
|
10513
10513
|
var IS_MERGE_FIELD = "_is_merge";
|
|
10514
|
+
var AUDIT_SOURCE_FIELD = "_audit_source";
|
|
10515
|
+
var AUDIT_METADATA_FIELD = "_audit_metadata";
|
|
10516
|
+
var VALID_SOURCES = ["app", "api", "external"];
|
|
10517
|
+
var PARENT_ID_FIELD = "_parent_id";
|
|
10514
10518
|
function mergeDicts(mergeInto, mergeFrom) {
|
|
10515
10519
|
for (const [k, mergeFromV] of Object.entries(mergeFrom)) {
|
|
10516
10520
|
const mergeIntoV = mergeInto[k];
|
|
@@ -10523,6 +10527,7 @@ function mergeDicts(mergeInto, mergeFrom) {
|
|
|
10523
10527
|
mergeInto[k] = mergeFromV;
|
|
10524
10528
|
}
|
|
10525
10529
|
}
|
|
10530
|
+
return mergeInto;
|
|
10526
10531
|
}
|
|
10527
10532
|
function generateMergedRowKey(row) {
|
|
10528
10533
|
return JSON.stringify(
|
|
@@ -10564,6 +10569,15 @@ function mergeRowBatch(rows) {
|
|
|
10564
10569
|
out.push(...Object.values(rowGroups));
|
|
10565
10570
|
return out;
|
|
10566
10571
|
}
|
|
10572
|
+
var SpanTypeAttribute = /* @__PURE__ */ ((SpanTypeAttribute2) => {
|
|
10573
|
+
SpanTypeAttribute2["LLM"] = "llm";
|
|
10574
|
+
SpanTypeAttribute2["SCORE"] = "score";
|
|
10575
|
+
SpanTypeAttribute2["FUNCTION"] = "function";
|
|
10576
|
+
SpanTypeAttribute2["EVAL"] = "eval";
|
|
10577
|
+
SpanTypeAttribute2["TASK"] = "task";
|
|
10578
|
+
SpanTypeAttribute2["TOOL"] = "tool";
|
|
10579
|
+
return SpanTypeAttribute2;
|
|
10580
|
+
})(SpanTypeAttribute || {});
|
|
10567
10581
|
|
|
10568
10582
|
// src/isomorph.ts
|
|
10569
10583
|
var DefaultAsyncLocalStorage = class {
|
|
@@ -10609,6 +10623,9 @@ function runFinally(f, finallyF) {
|
|
|
10609
10623
|
function getCurrentUnixTimestamp() {
|
|
10610
10624
|
return (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
10611
10625
|
}
|
|
10626
|
+
function isEmpty(a) {
|
|
10627
|
+
return a === void 0 || a === null;
|
|
10628
|
+
}
|
|
10612
10629
|
|
|
10613
10630
|
// src/logger.ts
|
|
10614
10631
|
var NoopSpan = class {
|
|
@@ -10620,6 +10637,8 @@ var NoopSpan = class {
|
|
|
10620
10637
|
}
|
|
10621
10638
|
log(_) {
|
|
10622
10639
|
}
|
|
10640
|
+
logFeedback(event) {
|
|
10641
|
+
}
|
|
10623
10642
|
traced(callback, _1) {
|
|
10624
10643
|
return callback(this);
|
|
10625
10644
|
}
|
|
@@ -10794,6 +10813,70 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
10794
10813
|
return await resp.json();
|
|
10795
10814
|
}
|
|
10796
10815
|
};
|
|
10816
|
+
function logFeedbackImpl(bgLogger, parentIds, {
|
|
10817
|
+
id,
|
|
10818
|
+
expected,
|
|
10819
|
+
scores,
|
|
10820
|
+
metadata: inputMetadata,
|
|
10821
|
+
comment,
|
|
10822
|
+
source: inputSource
|
|
10823
|
+
}) {
|
|
10824
|
+
const source = inputSource ?? "external";
|
|
10825
|
+
if (!VALID_SOURCES.includes(source)) {
|
|
10826
|
+
throw new Error(`source must be one of ${VALID_SOURCES}`);
|
|
10827
|
+
}
|
|
10828
|
+
if (isEmpty(scores) && isEmpty(expected) && isEmpty(comment)) {
|
|
10829
|
+
throw new Error(
|
|
10830
|
+
"At least one of scores, expected, or comment must be specified"
|
|
10831
|
+
);
|
|
10832
|
+
}
|
|
10833
|
+
const validatedEvent = validateAndSanitizeExperimentLogPartialArgs({
|
|
10834
|
+
scores,
|
|
10835
|
+
metadata: inputMetadata,
|
|
10836
|
+
expected
|
|
10837
|
+
});
|
|
10838
|
+
let { metadata, ...updateEvent } = validatedEvent;
|
|
10839
|
+
updateEvent = Object.fromEntries(
|
|
10840
|
+
Object.entries(updateEvent).filter(([_, v]) => !isEmpty(v))
|
|
10841
|
+
);
|
|
10842
|
+
const trueParentIds = (async () => {
|
|
10843
|
+
const { kind, ...ids } = await parentIds;
|
|
10844
|
+
return ids;
|
|
10845
|
+
})();
|
|
10846
|
+
if (Object.keys(updateEvent).length > 0) {
|
|
10847
|
+
const record = (async () => {
|
|
10848
|
+
return {
|
|
10849
|
+
id,
|
|
10850
|
+
...updateEvent,
|
|
10851
|
+
...await trueParentIds,
|
|
10852
|
+
[AUDIT_SOURCE_FIELD]: source,
|
|
10853
|
+
[AUDIT_METADATA_FIELD]: metadata,
|
|
10854
|
+
[IS_MERGE_FIELD]: true
|
|
10855
|
+
};
|
|
10856
|
+
})();
|
|
10857
|
+
bgLogger.log([record]);
|
|
10858
|
+
}
|
|
10859
|
+
if (!isEmpty(comment)) {
|
|
10860
|
+
const record = (async () => {
|
|
10861
|
+
return {
|
|
10862
|
+
id: v4_default(),
|
|
10863
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10864
|
+
origin: {
|
|
10865
|
+
// NOTE: We do not know (or care?) what the transaction id of the row that
|
|
10866
|
+
// we're commenting on is here, so we omit it.
|
|
10867
|
+
id
|
|
10868
|
+
},
|
|
10869
|
+
comment: {
|
|
10870
|
+
text: comment
|
|
10871
|
+
},
|
|
10872
|
+
...await trueParentIds,
|
|
10873
|
+
[AUDIT_SOURCE_FIELD]: source,
|
|
10874
|
+
[AUDIT_METADATA_FIELD]: metadata
|
|
10875
|
+
};
|
|
10876
|
+
})();
|
|
10877
|
+
bgLogger.log([record]);
|
|
10878
|
+
}
|
|
10879
|
+
}
|
|
10797
10880
|
var MaxRequestSize = 6 * 1024 * 1024;
|
|
10798
10881
|
function constructJsonArray(items) {
|
|
10799
10882
|
return `[${items.join(",")}]`;
|
|
@@ -11177,6 +11260,13 @@ var Experiment = class {
|
|
|
11177
11260
|
() => span.end()
|
|
11178
11261
|
);
|
|
11179
11262
|
}
|
|
11263
|
+
async lazyParentIds() {
|
|
11264
|
+
return {
|
|
11265
|
+
kind: "experiment",
|
|
11266
|
+
project_id: (await this.project).id,
|
|
11267
|
+
experiment_id: await this.id
|
|
11268
|
+
};
|
|
11269
|
+
}
|
|
11180
11270
|
/**
|
|
11181
11271
|
* Lower-level alternative to `traced`, which does not automatically end the span or mark it as current.
|
|
11182
11272
|
*
|
|
@@ -11184,13 +11274,8 @@ var Experiment = class {
|
|
|
11184
11274
|
*/
|
|
11185
11275
|
startSpan(args) {
|
|
11186
11276
|
const { name, ...argsRest } = args ?? {};
|
|
11187
|
-
const parentIds = (async () => ({
|
|
11188
|
-
kind: "experiment",
|
|
11189
|
-
project_id: (await this.project).id,
|
|
11190
|
-
experiment_id: await this.id
|
|
11191
|
-
}))();
|
|
11192
11277
|
return new SpanImpl({
|
|
11193
|
-
parentIds,
|
|
11278
|
+
parentIds: this.lazyParentIds(),
|
|
11194
11279
|
bgLogger: this.bgLogger,
|
|
11195
11280
|
name: name ?? "root",
|
|
11196
11281
|
...argsRest
|
|
@@ -11252,6 +11337,20 @@ var Experiment = class {
|
|
|
11252
11337
|
metrics
|
|
11253
11338
|
};
|
|
11254
11339
|
}
|
|
11340
|
+
/**
|
|
11341
|
+
* Log feedback to an event in the experiment. Feedback is used to save feedback scores, set an expected value, or add a comment.
|
|
11342
|
+
*
|
|
11343
|
+
* @param event
|
|
11344
|
+
* @param event.id The id of the event to log feedback for. This is the `id` returned by `log` or accessible as the `id` field of a span.
|
|
11345
|
+
* @param event.scores (Optional) a dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the existing scores for the event.
|
|
11346
|
+
* @param event.expected (Optional) the ground truth value (an arbitrary, JSON serializable object) that you'd compare to `output` to determine if your `output` value is correct or not.
|
|
11347
|
+
* @param event.comment (Optional) an optional comment string to log about the event.
|
|
11348
|
+
* @param event.metadata (Optional) a dictionary with additional data about the feedback. If you have a `user_id`, you can log it here and access it in the Braintrust UI.
|
|
11349
|
+
* @param event.source (Optional) the source of the feedback. Must be one of "external" (default), "app", or "api".
|
|
11350
|
+
*/
|
|
11351
|
+
logFeedback(event) {
|
|
11352
|
+
logFeedbackImpl(this.bgLogger, this.lazyParentIds(), event);
|
|
11353
|
+
}
|
|
11255
11354
|
/**
|
|
11256
11355
|
* Flush any pending rows to the server.
|
|
11257
11356
|
*/
|
|
@@ -11302,10 +11401,12 @@ var SpanImpl = class _SpanImpl {
|
|
|
11302
11401
|
this.rowIds = {
|
|
11303
11402
|
id,
|
|
11304
11403
|
span_id,
|
|
11305
|
-
root_span_id: args.parentSpanInfo?.root_span_id
|
|
11404
|
+
root_span_id: "parentSpanInfo" in args && args.parentSpanInfo?.root_span_id ? args.parentSpanInfo.root_span_id : span_id
|
|
11306
11405
|
};
|
|
11307
|
-
if (args.parentSpanInfo) {
|
|
11406
|
+
if ("parentSpanInfo" in args && args.parentSpanInfo?.span_id) {
|
|
11308
11407
|
this.internalData.span_parents = [args.parentSpanInfo.span_id];
|
|
11408
|
+
} else if ("parentId" in args && !isEmpty(args.parentId)) {
|
|
11409
|
+
this.rowIds[PARENT_ID_FIELD] = args.parentId;
|
|
11309
11410
|
}
|
|
11310
11411
|
this.isMerge = false;
|
|
11311
11412
|
const { id: _id, ...eventRest } = args.event ?? {};
|
|
@@ -11329,16 +11430,26 @@ var SpanImpl = class _SpanImpl {
|
|
|
11329
11430
|
if (sanitizedAndInternalData.metrics?.end) {
|
|
11330
11431
|
this.loggedEndTime = sanitizedAndInternalData.metrics?.end;
|
|
11331
11432
|
}
|
|
11433
|
+
const parentIds = (async () => {
|
|
11434
|
+
const { kind, ...ids } = await this.parentIds;
|
|
11435
|
+
return ids;
|
|
11436
|
+
})();
|
|
11332
11437
|
const record = (async () => {
|
|
11333
11438
|
return {
|
|
11334
11439
|
...sanitizedAndInternalData,
|
|
11335
11440
|
...this.rowIds,
|
|
11336
|
-
...await
|
|
11441
|
+
...await parentIds,
|
|
11337
11442
|
[IS_MERGE_FIELD]: this.isMerge
|
|
11338
11443
|
};
|
|
11339
11444
|
})();
|
|
11340
11445
|
this.bgLogger.log([record]);
|
|
11341
11446
|
}
|
|
11447
|
+
logFeedback(event) {
|
|
11448
|
+
logFeedbackImpl(this.bgLogger, this.parentIds, {
|
|
11449
|
+
...event,
|
|
11450
|
+
id: this.id
|
|
11451
|
+
});
|
|
11452
|
+
}
|
|
11342
11453
|
traced(callback, args) {
|
|
11343
11454
|
const { setCurrent, ...argsRest } = args ?? {};
|
|
11344
11455
|
const span = this.startSpan(argsRest);
|
|
@@ -11771,7 +11882,7 @@ async function runEvaluator(experiment, evaluator, progressReporter, filters) {
|
|
|
11771
11882
|
}
|
|
11772
11883
|
span.log({ input: datum.input, output });
|
|
11773
11884
|
},
|
|
11774
|
-
{ name: "task" }
|
|
11885
|
+
{ name: "task", spanAttributes: { type: SpanTypeAttribute.TASK } }
|
|
11775
11886
|
);
|
|
11776
11887
|
rootSpan.log({ output });
|
|
11777
11888
|
const scoringArgs = { ...datum, metadata, output };
|
|
@@ -11794,6 +11905,9 @@ async function runEvaluator(experiment, evaluator, progressReporter, filters) {
|
|
|
11794
11905
|
},
|
|
11795
11906
|
{
|
|
11796
11907
|
name: score.name || `scorer_${score_idx}`,
|
|
11908
|
+
spanAttributes: {
|
|
11909
|
+
type: SpanTypeAttribute.SCORE
|
|
11910
|
+
},
|
|
11797
11911
|
event: { input: scoringArgs }
|
|
11798
11912
|
}
|
|
11799
11913
|
);
|
|
@@ -11833,6 +11947,9 @@ async function runEvaluator(experiment, evaluator, progressReporter, filters) {
|
|
|
11833
11947
|
} else {
|
|
11834
11948
|
return await experiment.traced(callback, {
|
|
11835
11949
|
name: "eval",
|
|
11950
|
+
spanAttributes: {
|
|
11951
|
+
type: SpanTypeAttribute.EVAL
|
|
11952
|
+
},
|
|
11836
11953
|
event: {
|
|
11837
11954
|
input: datum.input,
|
|
11838
11955
|
expected: datum.expected
|
|
@@ -15985,7 +16102,9 @@ async function getRepoStatus() {
|
|
|
15985
16102
|
async () => (await git.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim()
|
|
15986
16103
|
);
|
|
15987
16104
|
if (dirty) {
|
|
15988
|
-
git_diff = await attempt(
|
|
16105
|
+
git_diff = await attempt(
|
|
16106
|
+
async () => truncateToByteLimit(await git.raw(["diff", "HEAD"]))
|
|
16107
|
+
);
|
|
15989
16108
|
}
|
|
15990
16109
|
return {
|
|
15991
16110
|
commit,
|