braintrust 0.0.166 → 0.0.167
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.d.mts +135 -39
- package/dist/browser.d.ts +135 -39
- package/dist/browser.js +317 -85
- package/dist/browser.mjs +318 -87
- package/dist/cli.js +299 -65
- package/dist/index.d.mts +135 -39
- package/dist/index.d.ts +135 -39
- package/dist/index.js +318 -85
- package/dist/index.mjs +319 -87
- package/package.json +7 -2
- package/typedoc.json +1 -0
package/dist/browser.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/browser.ts
|
|
31
31
|
var browser_exports = {};
|
|
32
32
|
__export(browser_exports, {
|
|
33
|
+
Attachment: () => Attachment,
|
|
33
34
|
BraintrustState: () => BraintrustState,
|
|
34
35
|
BraintrustStream: () => BraintrustStream,
|
|
35
36
|
Dataset: () => Dataset,
|
|
@@ -43,6 +44,7 @@ __export(browser_exports, {
|
|
|
43
44
|
ReadonlyExperiment: () => ReadonlyExperiment,
|
|
44
45
|
SpanImpl: () => SpanImpl,
|
|
45
46
|
X_CACHED_HEADER: () => X_CACHED_HEADER,
|
|
47
|
+
_exportsForTestingOnly: () => _exportsForTestingOnly,
|
|
46
48
|
_internalGetGlobalState: () => _internalGetGlobalState,
|
|
47
49
|
_internalSetInitialState: () => _internalSetInitialState,
|
|
48
50
|
braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
|
|
@@ -587,11 +589,11 @@ var BraintrustState = class _BraintrustState {
|
|
|
587
589
|
state.loginReplaceApiConn(state.apiConn());
|
|
588
590
|
return state;
|
|
589
591
|
}
|
|
590
|
-
setFetch(
|
|
591
|
-
this.loginParams.fetch =
|
|
592
|
-
this.fetch =
|
|
593
|
-
this._apiConn?.setFetch(
|
|
594
|
-
this._appConn?.setFetch(
|
|
592
|
+
setFetch(fetch2) {
|
|
593
|
+
this.loginParams.fetch = fetch2;
|
|
594
|
+
this.fetch = fetch2;
|
|
595
|
+
this._apiConn?.setFetch(fetch2);
|
|
596
|
+
this._appConn?.setFetch(fetch2);
|
|
595
597
|
}
|
|
596
598
|
async login(loginParams) {
|
|
597
599
|
if (this.apiUrl && !loginParams.forceLogin) {
|
|
@@ -680,15 +682,15 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
680
682
|
token;
|
|
681
683
|
headers;
|
|
682
684
|
fetch;
|
|
683
|
-
constructor(base_url,
|
|
685
|
+
constructor(base_url, fetch2) {
|
|
684
686
|
this.base_url = base_url;
|
|
685
687
|
this.token = null;
|
|
686
688
|
this.headers = {};
|
|
687
689
|
this._reset();
|
|
688
|
-
this.fetch =
|
|
690
|
+
this.fetch = fetch2;
|
|
689
691
|
}
|
|
690
|
-
setFetch(
|
|
691
|
-
this.fetch =
|
|
692
|
+
setFetch(fetch2) {
|
|
693
|
+
this.fetch = fetch2;
|
|
692
694
|
}
|
|
693
695
|
async ping() {
|
|
694
696
|
try {
|
|
@@ -724,12 +726,14 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
724
726
|
([k, v]) => v !== void 0 ? typeof v === "string" ? [[k, v]] : v.map((x) => [k, x]) : []
|
|
725
727
|
) : []
|
|
726
728
|
).toString();
|
|
729
|
+
const this_fetch = this.fetch;
|
|
730
|
+
const this_headers = this.headers;
|
|
727
731
|
return await checkResponse(
|
|
728
732
|
// Using toString() here makes it work with isomorphic fetch
|
|
729
|
-
await
|
|
733
|
+
await this_fetch(url.toString(), {
|
|
730
734
|
headers: {
|
|
731
735
|
Accept: "application/json",
|
|
732
|
-
...
|
|
736
|
+
...this_headers,
|
|
733
737
|
...headers
|
|
734
738
|
},
|
|
735
739
|
keepalive: true,
|
|
@@ -739,13 +743,16 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
739
743
|
}
|
|
740
744
|
async post(path, params, config) {
|
|
741
745
|
const { headers, ...rest } = config || {};
|
|
746
|
+
const this_fetch = this.fetch;
|
|
747
|
+
const this_base_url = this.base_url;
|
|
748
|
+
const this_headers = this.headers;
|
|
742
749
|
return await checkResponse(
|
|
743
|
-
await
|
|
750
|
+
await this_fetch((0, import_core._urljoin)(this_base_url, path), {
|
|
744
751
|
method: "POST",
|
|
745
752
|
headers: {
|
|
746
753
|
Accept: "application/json",
|
|
747
754
|
"Content-Type": "application/json",
|
|
748
|
-
...
|
|
755
|
+
...this_headers,
|
|
749
756
|
...headers
|
|
750
757
|
},
|
|
751
758
|
body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
|
|
@@ -778,6 +785,167 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
778
785
|
return await resp.json();
|
|
779
786
|
}
|
|
780
787
|
};
|
|
788
|
+
var Attachment = class {
|
|
789
|
+
/**
|
|
790
|
+
* The object that replaces this `Attachment` at upload time.
|
|
791
|
+
*/
|
|
792
|
+
reference;
|
|
793
|
+
uploader;
|
|
794
|
+
data;
|
|
795
|
+
state;
|
|
796
|
+
// For debug logging only.
|
|
797
|
+
dataDebugString;
|
|
798
|
+
/**
|
|
799
|
+
* Construct an attachment.
|
|
800
|
+
*
|
|
801
|
+
* @param data A string representing the path of the file on disk, or a
|
|
802
|
+
* `Blob`/`ArrayBuffer` with the file's contents. The caller is responsible
|
|
803
|
+
* for ensuring the file/blob/buffer is not modified until upload is complete.
|
|
804
|
+
*
|
|
805
|
+
* @param filename The desired name of the file in Braintrust after uploading.
|
|
806
|
+
* This parameter is for visualization purposes only and has no effect on
|
|
807
|
+
* attachment storage.
|
|
808
|
+
*
|
|
809
|
+
* @param contentType The MIME type of the file.
|
|
810
|
+
*
|
|
811
|
+
* @param state (Optional) For internal use.
|
|
812
|
+
*/
|
|
813
|
+
constructor({ data, filename, contentType, state }) {
|
|
814
|
+
this.reference = {
|
|
815
|
+
type: import_typespecs2.BRAINTRUST_ATTACHMENT,
|
|
816
|
+
filename,
|
|
817
|
+
content_type: contentType,
|
|
818
|
+
key: newId()
|
|
819
|
+
};
|
|
820
|
+
this.state = state;
|
|
821
|
+
this.dataDebugString = typeof data === "string" ? data : "<in-memory data>";
|
|
822
|
+
this.data = this.initData(data);
|
|
823
|
+
this.uploader = this.initUploader();
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* On first access, (1) reads the attachment from disk if needed, (2)
|
|
827
|
+
* authenticates with the data plane to request a signed URL, (3) uploads to
|
|
828
|
+
* object store, and (4) updates the attachment.
|
|
829
|
+
*
|
|
830
|
+
* @returns The attachment status.
|
|
831
|
+
*/
|
|
832
|
+
async upload() {
|
|
833
|
+
return await this.uploader.get();
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* A human-readable description for logging and debugging.
|
|
837
|
+
*
|
|
838
|
+
* @returns The debug object. The return type is not stable and may change in
|
|
839
|
+
* a future release.
|
|
840
|
+
*/
|
|
841
|
+
debugInfo() {
|
|
842
|
+
return {
|
|
843
|
+
inputData: this.dataDebugString,
|
|
844
|
+
reference: this.reference,
|
|
845
|
+
state: this.state
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
initUploader() {
|
|
849
|
+
const doUpload = async (conn, orgId) => {
|
|
850
|
+
const requestParams = {
|
|
851
|
+
key: this.reference.key,
|
|
852
|
+
filename: this.reference.filename,
|
|
853
|
+
content_type: this.reference.content_type,
|
|
854
|
+
org_id: orgId
|
|
855
|
+
};
|
|
856
|
+
const [metadataPromiseResult, dataPromiseResult] = await Promise.allSettled([
|
|
857
|
+
conn.post("/attachment", requestParams),
|
|
858
|
+
this.data.get()
|
|
859
|
+
]);
|
|
860
|
+
if (metadataPromiseResult.status === "rejected") {
|
|
861
|
+
const errorStr = JSON.stringify(metadataPromiseResult.reason);
|
|
862
|
+
throw new Error(
|
|
863
|
+
`Failed to request signed URL from API server: ${errorStr}`
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
if (dataPromiseResult.status === "rejected") {
|
|
867
|
+
const errorStr = JSON.stringify(dataPromiseResult.reason);
|
|
868
|
+
throw new Error(`Failed to read file: ${errorStr}`);
|
|
869
|
+
}
|
|
870
|
+
const metadataResponse = metadataPromiseResult.value;
|
|
871
|
+
const data = dataPromiseResult.value;
|
|
872
|
+
let signedUrl;
|
|
873
|
+
let headers;
|
|
874
|
+
try {
|
|
875
|
+
({ signedUrl, headers } = import_zod2.z.object({
|
|
876
|
+
signedUrl: import_zod2.z.string().url(),
|
|
877
|
+
headers: import_zod2.z.record(import_zod2.z.string())
|
|
878
|
+
}).parse(await metadataResponse.json()));
|
|
879
|
+
} catch (error) {
|
|
880
|
+
if (error instanceof import_zod2.ZodError) {
|
|
881
|
+
const errorStr = JSON.stringify(error.flatten());
|
|
882
|
+
throw new Error(`Invalid response from API server: ${errorStr}`);
|
|
883
|
+
}
|
|
884
|
+
throw error;
|
|
885
|
+
}
|
|
886
|
+
let objectStoreResponse;
|
|
887
|
+
try {
|
|
888
|
+
objectStoreResponse = await checkResponse(
|
|
889
|
+
await fetch(signedUrl, {
|
|
890
|
+
method: "PUT",
|
|
891
|
+
headers,
|
|
892
|
+
body: data
|
|
893
|
+
})
|
|
894
|
+
);
|
|
895
|
+
} catch (error) {
|
|
896
|
+
if (error instanceof FailedHTTPResponse) {
|
|
897
|
+
throw new Error(
|
|
898
|
+
`Failed to upload attachment to object store: ${error.status} ${error.text} ${error.data}`
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
throw error;
|
|
902
|
+
}
|
|
903
|
+
return { signedUrl, metadataResponse, objectStoreResponse };
|
|
904
|
+
};
|
|
905
|
+
const errorWrapper = async () => {
|
|
906
|
+
const status = { upload_status: "done" };
|
|
907
|
+
const state = this.state ?? _globalState;
|
|
908
|
+
await state.login({});
|
|
909
|
+
const conn = state.apiConn();
|
|
910
|
+
const orgId = state.orgId ?? "";
|
|
911
|
+
try {
|
|
912
|
+
await doUpload(conn, orgId);
|
|
913
|
+
} catch (error) {
|
|
914
|
+
status.upload_status = "error";
|
|
915
|
+
status.error_message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
916
|
+
}
|
|
917
|
+
const requestParams = {
|
|
918
|
+
key: this.reference.key,
|
|
919
|
+
org_id: orgId,
|
|
920
|
+
status
|
|
921
|
+
};
|
|
922
|
+
const statusResponse = await conn.post(
|
|
923
|
+
"/attachment/status",
|
|
924
|
+
requestParams
|
|
925
|
+
);
|
|
926
|
+
if (!statusResponse.ok) {
|
|
927
|
+
const errorStr = JSON.stringify(statusResponse);
|
|
928
|
+
throw new Error(`Couldn't log attachment status: ${errorStr}`);
|
|
929
|
+
}
|
|
930
|
+
return status;
|
|
931
|
+
};
|
|
932
|
+
return new LazyValue(errorWrapper);
|
|
933
|
+
}
|
|
934
|
+
initData(data) {
|
|
935
|
+
if (typeof data === "string") {
|
|
936
|
+
const readFile = isomorph_default.readFile;
|
|
937
|
+
if (!readFile) {
|
|
938
|
+
throw new Error(
|
|
939
|
+
`This platform does not support reading the filesystem. Construct the Attachment
|
|
940
|
+
with a Blob/ArrayBuffer, or run the program on Node.js.`
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
return new LazyValue(async () => new Blob([await readFile(data)]));
|
|
944
|
+
} else {
|
|
945
|
+
return new LazyValue(async () => new Blob([data]));
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
};
|
|
781
949
|
function logFeedbackImpl(state, parentObjectType, parentObjectId, {
|
|
782
950
|
id,
|
|
783
951
|
expected,
|
|
@@ -802,7 +970,7 @@ function logFeedbackImpl(state, parentObjectType, parentObjectId, {
|
|
|
802
970
|
expected,
|
|
803
971
|
tags
|
|
804
972
|
});
|
|
805
|
-
let { metadata, ...updateEvent } = validatedEvent;
|
|
973
|
+
let { metadata, ...updateEvent } = deepCopyEvent(validatedEvent);
|
|
806
974
|
updateEvent = Object.fromEntries(
|
|
807
975
|
Object.entries(updateEvent).filter(([_, v]) => !isEmpty(v))
|
|
808
976
|
);
|
|
@@ -851,10 +1019,12 @@ function updateSpanImpl({
|
|
|
851
1019
|
id,
|
|
852
1020
|
event
|
|
853
1021
|
}) {
|
|
854
|
-
const updateEvent =
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1022
|
+
const updateEvent = deepCopyEvent(
|
|
1023
|
+
validateAndSanitizeExperimentLogPartialArgs({
|
|
1024
|
+
id,
|
|
1025
|
+
...event
|
|
1026
|
+
})
|
|
1027
|
+
);
|
|
858
1028
|
const parentIds = async () => new import_core.SpanComponentsV3({
|
|
859
1029
|
object_type: parentObjectType,
|
|
860
1030
|
object_id: await parentObjectId.get()
|
|
@@ -1055,7 +1225,7 @@ var Logger = class {
|
|
|
1055
1225
|
* @param event.id: (Optional) a unique identifier for the event. If you don't provide one, BrainTrust will generate one for you.
|
|
1056
1226
|
* @param options Additional logging options
|
|
1057
1227
|
* @param options.allowConcurrentWithSpans in rare cases where you need to log at the top level separately from spans on the logger elsewhere, set this to true.
|
|
1058
|
-
*
|
|
1228
|
+
* @returns The `id` of the logged event.
|
|
1059
1229
|
*/
|
|
1060
1230
|
log(event, options) {
|
|
1061
1231
|
if (this.calledStartSpan && !options?.allowConcurrentWithSpans) {
|
|
@@ -1078,7 +1248,7 @@ var Logger = class {
|
|
|
1078
1248
|
/**
|
|
1079
1249
|
* Create a new toplevel span underneath the logger. The name defaults to "root".
|
|
1080
1250
|
*
|
|
1081
|
-
* See
|
|
1251
|
+
* See {@link Span.traced} for full details.
|
|
1082
1252
|
*/
|
|
1083
1253
|
traced(callback, args) {
|
|
1084
1254
|
const { setCurrent, ...argsRest } = args ?? {};
|
|
@@ -1112,7 +1282,7 @@ var Logger = class {
|
|
|
1112
1282
|
* where you cannot use callbacks. However, spans started with `startSpan` will not be marked as the "current span",
|
|
1113
1283
|
* so `currentSpan()` and `traced()` will be no-ops. If you want to mark a span as current, use `traced` instead.
|
|
1114
1284
|
*
|
|
1115
|
-
* See
|
|
1285
|
+
* See {@link traced} for full details.
|
|
1116
1286
|
*/
|
|
1117
1287
|
startSpan(args) {
|
|
1118
1288
|
this.calledStartSpan = true;
|
|
@@ -1152,7 +1322,7 @@ var Logger = class {
|
|
|
1152
1322
|
* Update a span in the experiment using its id. It is important that you only update a span once the original span has been fully written and flushed,
|
|
1153
1323
|
* since otherwise updates to the span may conflict with the original span.
|
|
1154
1324
|
*
|
|
1155
|
-
* @param event The event data to update the span with. Must include `id`. See
|
|
1325
|
+
* @param event The event data to update the span with. Must include `id`. See {@link Experiment.log} for a full list of valid fields.
|
|
1156
1326
|
*/
|
|
1157
1327
|
updateSpan(event) {
|
|
1158
1328
|
const { id, ...eventRest } = event;
|
|
@@ -1168,7 +1338,9 @@ var Logger = class {
|
|
|
1168
1338
|
});
|
|
1169
1339
|
}
|
|
1170
1340
|
/**
|
|
1171
|
-
* Return a serialized representation of the logger that can be used to start subspans in other places.
|
|
1341
|
+
* Return a serialized representation of the logger that can be used to start subspans in other places.
|
|
1342
|
+
*
|
|
1343
|
+
* See {@link Span.startSpan} for more details.
|
|
1172
1344
|
*/
|
|
1173
1345
|
async export() {
|
|
1174
1346
|
return new import_core.SpanComponentsV3({
|
|
@@ -1309,7 +1481,7 @@ var BackgroundLogger = class _BackgroundLogger {
|
|
|
1309
1481
|
const batchSize = args?.batchSize ?? this.defaultBatchSize;
|
|
1310
1482
|
const wrappedItems = this.items;
|
|
1311
1483
|
this.items = [];
|
|
1312
|
-
const allItems = await this.unwrapLazyValues(wrappedItems);
|
|
1484
|
+
const [allItems, attachments] = await this.unwrapLazyValues(wrappedItems);
|
|
1313
1485
|
if (allItems.length === 0) {
|
|
1314
1486
|
return;
|
|
1315
1487
|
}
|
|
@@ -1341,6 +1513,23 @@ var BackgroundLogger = class _BackgroundLogger {
|
|
|
1341
1513
|
);
|
|
1342
1514
|
}
|
|
1343
1515
|
}
|
|
1516
|
+
const attachmentErrors = [];
|
|
1517
|
+
for (const attachment of attachments) {
|
|
1518
|
+
try {
|
|
1519
|
+
const result = await attachment.upload();
|
|
1520
|
+
if (result.upload_status === "error" && result.error_message) {
|
|
1521
|
+
attachmentErrors.push(new Error(result.error_message));
|
|
1522
|
+
}
|
|
1523
|
+
} catch (error) {
|
|
1524
|
+
attachmentErrors.push(error);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
if (attachmentErrors.length > 0) {
|
|
1528
|
+
throw new AggregateError(
|
|
1529
|
+
attachmentErrors,
|
|
1530
|
+
`Encountered the following errors while uploading attachments:`
|
|
1531
|
+
);
|
|
1532
|
+
}
|
|
1344
1533
|
if (this.items.length > 0) {
|
|
1345
1534
|
await this.flushOnce(args);
|
|
1346
1535
|
}
|
|
@@ -1348,8 +1537,10 @@ var BackgroundLogger = class _BackgroundLogger {
|
|
|
1348
1537
|
async unwrapLazyValues(wrappedItems) {
|
|
1349
1538
|
for (let i = 0; i < this.numTries; ++i) {
|
|
1350
1539
|
try {
|
|
1351
|
-
const
|
|
1352
|
-
|
|
1540
|
+
const items = await Promise.all(wrappedItems.map((x) => x.get()));
|
|
1541
|
+
const attachments = [];
|
|
1542
|
+
items.forEach((item) => extractAttachments(item, attachments));
|
|
1543
|
+
return [(0, import_core.mergeRowBatch)(items), attachments];
|
|
1353
1544
|
} catch (e) {
|
|
1354
1545
|
let errmsg = "Encountered error when constructing records to flush";
|
|
1355
1546
|
const isRetrying = i + 1 < this.numTries;
|
|
@@ -1368,7 +1559,7 @@ var BackgroundLogger = class _BackgroundLogger {
|
|
|
1368
1559
|
console.warn(
|
|
1369
1560
|
`Failed to construct log records to flush after ${this.numTries} attempts. Dropping batch`
|
|
1370
1561
|
);
|
|
1371
|
-
return [];
|
|
1562
|
+
return [[], []];
|
|
1372
1563
|
}
|
|
1373
1564
|
async submitLogsRequest(items) {
|
|
1374
1565
|
const conn = await this.apiConn.get();
|
|
@@ -1457,15 +1648,17 @@ Error: ${errorText}`;
|
|
|
1457
1648
|
return;
|
|
1458
1649
|
}
|
|
1459
1650
|
try {
|
|
1460
|
-
const allItems = await this.unwrapLazyValues(wrappedItems);
|
|
1651
|
+
const [allItems, allAttachments] = await this.unwrapLazyValues(wrappedItems);
|
|
1461
1652
|
const dataStr = constructLogs3Data(
|
|
1462
1653
|
allItems.map((x) => JSON.stringify(x))
|
|
1463
1654
|
);
|
|
1655
|
+
const attachmentStr = JSON.stringify(
|
|
1656
|
+
allAttachments.map((a) => a.debugInfo())
|
|
1657
|
+
);
|
|
1658
|
+
const payload = `{"data": ${dataStr}, "attachments": ${attachmentStr}}
|
|
1659
|
+
`;
|
|
1464
1660
|
for (const payloadDir of publishPayloadsDir) {
|
|
1465
|
-
await _BackgroundLogger.writePayloadToDir({
|
|
1466
|
-
payloadDir,
|
|
1467
|
-
payload: dataStr
|
|
1468
|
-
});
|
|
1661
|
+
await _BackgroundLogger.writePayloadToDir({ payloadDir, payload });
|
|
1469
1662
|
}
|
|
1470
1663
|
} catch (e) {
|
|
1471
1664
|
console.error(e);
|
|
@@ -1546,7 +1739,7 @@ function init(projectOrOptions, optionalOptions) {
|
|
|
1546
1739
|
apiKey,
|
|
1547
1740
|
orgName,
|
|
1548
1741
|
forceLogin,
|
|
1549
|
-
fetch,
|
|
1742
|
+
fetch: fetch2,
|
|
1550
1743
|
metadata,
|
|
1551
1744
|
gitMetadataSettings,
|
|
1552
1745
|
projectId,
|
|
@@ -1564,7 +1757,7 @@ function init(projectOrOptions, optionalOptions) {
|
|
|
1564
1757
|
}
|
|
1565
1758
|
const lazyMetadata2 = new LazyValue(
|
|
1566
1759
|
async () => {
|
|
1567
|
-
await state.login({ apiKey, appUrl, orgName, fetch, forceLogin });
|
|
1760
|
+
await state.login({ apiKey, appUrl, orgName, fetch: fetch2, forceLogin });
|
|
1568
1761
|
const args = {
|
|
1569
1762
|
project_name: project,
|
|
1570
1763
|
project_id: projectId,
|
|
@@ -1735,7 +1928,7 @@ function initDataset(projectOrOptions, optionalOptions) {
|
|
|
1735
1928
|
appUrl,
|
|
1736
1929
|
apiKey,
|
|
1737
1930
|
orgName,
|
|
1738
|
-
fetch,
|
|
1931
|
+
fetch: fetch2,
|
|
1739
1932
|
forceLogin,
|
|
1740
1933
|
projectId,
|
|
1741
1934
|
metadata,
|
|
@@ -1749,7 +1942,7 @@ function initDataset(projectOrOptions, optionalOptions) {
|
|
|
1749
1942
|
orgName,
|
|
1750
1943
|
apiKey,
|
|
1751
1944
|
appUrl,
|
|
1752
|
-
fetch,
|
|
1945
|
+
fetch: fetch2,
|
|
1753
1946
|
forceLogin
|
|
1754
1947
|
});
|
|
1755
1948
|
const args = {
|
|
@@ -1831,7 +2024,7 @@ function initLogger(options = {}) {
|
|
|
1831
2024
|
apiKey,
|
|
1832
2025
|
orgName,
|
|
1833
2026
|
forceLogin,
|
|
1834
|
-
fetch,
|
|
2027
|
+
fetch: fetch2,
|
|
1835
2028
|
state: stateArg
|
|
1836
2029
|
} = options || {};
|
|
1837
2030
|
const computeMetadataArgs = {
|
|
@@ -1846,7 +2039,7 @@ function initLogger(options = {}) {
|
|
|
1846
2039
|
apiKey,
|
|
1847
2040
|
appUrl,
|
|
1848
2041
|
forceLogin,
|
|
1849
|
-
fetch
|
|
2042
|
+
fetch: fetch2
|
|
1850
2043
|
});
|
|
1851
2044
|
return computeLoggerMetadata(state, computeMetadataArgs);
|
|
1852
2045
|
}
|
|
@@ -1870,7 +2063,7 @@ async function loadPrompt({
|
|
|
1870
2063
|
appUrl,
|
|
1871
2064
|
apiKey,
|
|
1872
2065
|
orgName,
|
|
1873
|
-
fetch,
|
|
2066
|
+
fetch: fetch2,
|
|
1874
2067
|
forceLogin,
|
|
1875
2068
|
state: stateArg
|
|
1876
2069
|
}) {
|
|
@@ -1885,7 +2078,7 @@ async function loadPrompt({
|
|
|
1885
2078
|
orgName,
|
|
1886
2079
|
apiKey,
|
|
1887
2080
|
appUrl,
|
|
1888
|
-
fetch,
|
|
2081
|
+
fetch: fetch2,
|
|
1889
2082
|
forceLogin
|
|
1890
2083
|
});
|
|
1891
2084
|
const args = {
|
|
@@ -1936,7 +2129,7 @@ async function loginToState(options = {}) {
|
|
|
1936
2129
|
appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
|
|
1937
2130
|
apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
|
|
1938
2131
|
orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
|
|
1939
|
-
fetch = globalThis.fetch
|
|
2132
|
+
fetch: fetch2 = globalThis.fetch
|
|
1940
2133
|
} = options || {};
|
|
1941
2134
|
const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
|
|
1942
2135
|
const state = new BraintrustState(options);
|
|
@@ -1946,7 +2139,7 @@ async function loginToState(options = {}) {
|
|
|
1946
2139
|
let conn = null;
|
|
1947
2140
|
if (apiKey !== void 0) {
|
|
1948
2141
|
const resp = await checkResponse(
|
|
1949
|
-
await
|
|
2142
|
+
await fetch2((0, import_core._urljoin)(state.appUrl, `/api/apikey/login`), {
|
|
1950
2143
|
method: "POST",
|
|
1951
2144
|
headers: {
|
|
1952
2145
|
"Content-Type": "application/json",
|
|
@@ -2114,8 +2307,8 @@ async function flush(options) {
|
|
|
2114
2307
|
const state = options?.state ?? _globalState;
|
|
2115
2308
|
return await state.bgLogger().flush();
|
|
2116
2309
|
}
|
|
2117
|
-
function setFetch(
|
|
2118
|
-
_globalState.setFetch(
|
|
2310
|
+
function setFetch(fetch2) {
|
|
2311
|
+
_globalState.setFetch(fetch2);
|
|
2119
2312
|
}
|
|
2120
2313
|
function startSpanAndIsLogger(args) {
|
|
2121
2314
|
const state = args?.state ?? _globalState;
|
|
@@ -2243,6 +2436,47 @@ function validateAndSanitizeExperimentLogPartialArgs(event) {
|
|
|
2243
2436
|
return { ...event };
|
|
2244
2437
|
}
|
|
2245
2438
|
}
|
|
2439
|
+
function deepCopyEvent(event) {
|
|
2440
|
+
const attachments = [];
|
|
2441
|
+
const IDENTIFIER = "_bt_internal_saved_attachment";
|
|
2442
|
+
const savedAttachmentSchema = import_zod2.z.strictObject({ [IDENTIFIER]: import_zod2.z.number() });
|
|
2443
|
+
const serialized = JSON.stringify(event, (_k, v) => {
|
|
2444
|
+
if (v instanceof SpanImpl || v instanceof NoopSpan) {
|
|
2445
|
+
return `<span>`;
|
|
2446
|
+
} else if (v instanceof Experiment) {
|
|
2447
|
+
return `<experiment>`;
|
|
2448
|
+
} else if (v instanceof Dataset) {
|
|
2449
|
+
return `<dataset>`;
|
|
2450
|
+
} else if (v instanceof Logger) {
|
|
2451
|
+
return `<logger>`;
|
|
2452
|
+
} else if (v instanceof Attachment) {
|
|
2453
|
+
const idx = attachments.push(v);
|
|
2454
|
+
return { [IDENTIFIER]: idx - 1 };
|
|
2455
|
+
}
|
|
2456
|
+
return v;
|
|
2457
|
+
});
|
|
2458
|
+
const x = JSON.parse(serialized, (_k, v) => {
|
|
2459
|
+
const parsedAttachment = savedAttachmentSchema.safeParse(v);
|
|
2460
|
+
if (parsedAttachment.success) {
|
|
2461
|
+
return attachments[parsedAttachment.data[IDENTIFIER]];
|
|
2462
|
+
}
|
|
2463
|
+
return v;
|
|
2464
|
+
});
|
|
2465
|
+
return x;
|
|
2466
|
+
}
|
|
2467
|
+
function extractAttachments(event, attachments) {
|
|
2468
|
+
for (const [key, value] of Object.entries(event)) {
|
|
2469
|
+
if (value instanceof Attachment) {
|
|
2470
|
+
attachments.push(value);
|
|
2471
|
+
event[key] = value.reference;
|
|
2472
|
+
continue;
|
|
2473
|
+
}
|
|
2474
|
+
if (!(value instanceof Object)) {
|
|
2475
|
+
continue;
|
|
2476
|
+
}
|
|
2477
|
+
extractAttachments(value, attachments);
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2246
2480
|
function validateAndSanitizeExperimentLogFullArgs(event, hasDataset) {
|
|
2247
2481
|
if ("input" in event && !isEmpty(event.input) && "inputs" in event && !isEmpty(event.inputs) || !("input" in event) && !("inputs" in event)) {
|
|
2248
2482
|
throw new Error(
|
|
@@ -2373,10 +2607,10 @@ var Experiment = class extends ObjectFetcher {
|
|
|
2373
2607
|
* @param event.metrics: (Optional) a dictionary of metrics to log. The following keys are populated automatically: "start", "end".
|
|
2374
2608
|
* @param event.id: (Optional) a unique identifier for the event. If you don't provide one, BrainTrust will generate one for you.
|
|
2375
2609
|
* @param event.dataset_record_id: (Optional) the id of the dataset record that this event is associated with. This field is required if and only if the experiment is associated with a dataset.
|
|
2376
|
-
* @param event.inputs: (Deprecated) the same as `input` (will be removed in a future version).
|
|
2610
|
+
* @deprecated @param event.inputs: (Deprecated) the same as `input` (will be removed in a future version).
|
|
2377
2611
|
* @param options Additional logging options
|
|
2378
2612
|
* @param options.allowConcurrentWithSpans in rare cases where you need to log at the top level separately from spans on the experiment elsewhere, set this to true.
|
|
2379
|
-
*
|
|
2613
|
+
* @returns The `id` of the logged event.
|
|
2380
2614
|
*/
|
|
2381
2615
|
log(event, options) {
|
|
2382
2616
|
if (this.calledStartSpan && !options?.allowConcurrentWithSpans) {
|
|
@@ -2392,7 +2626,7 @@ var Experiment = class extends ObjectFetcher {
|
|
|
2392
2626
|
/**
|
|
2393
2627
|
* Create a new toplevel span underneath the experiment. The name defaults to "root".
|
|
2394
2628
|
*
|
|
2395
|
-
* See
|
|
2629
|
+
* See {@link Span.traced} for full details.
|
|
2396
2630
|
*/
|
|
2397
2631
|
traced(callback, args) {
|
|
2398
2632
|
const { setCurrent, ...argsRest } = args ?? {};
|
|
@@ -2418,7 +2652,7 @@ var Experiment = class extends ObjectFetcher {
|
|
|
2418
2652
|
* where you cannot use callbacks. However, spans started with `startSpan` will not be marked as the "current span",
|
|
2419
2653
|
* so `currentSpan()` and `traced()` will be no-ops. If you want to mark a span as current, use `traced` instead.
|
|
2420
2654
|
*
|
|
2421
|
-
* See
|
|
2655
|
+
* See {@link traced} for full details.
|
|
2422
2656
|
*/
|
|
2423
2657
|
startSpan(args) {
|
|
2424
2658
|
this.calledStartSpan = true;
|
|
@@ -2530,7 +2764,7 @@ var Experiment = class extends ObjectFetcher {
|
|
|
2530
2764
|
* Update a span in the experiment using its id. It is important that you only update a span once the original span has been fully written and flushed,
|
|
2531
2765
|
* since otherwise updates to the span may conflict with the original span.
|
|
2532
2766
|
*
|
|
2533
|
-
* @param event The event data to update the span with. Must include `id`. See
|
|
2767
|
+
* @param event The event data to update the span with. Must include `id`. See {@link Experiment.log} for a full list of valid fields.
|
|
2534
2768
|
*/
|
|
2535
2769
|
updateSpan(event) {
|
|
2536
2770
|
const { id, ...eventRest } = event;
|
|
@@ -2546,7 +2780,9 @@ var Experiment = class extends ObjectFetcher {
|
|
|
2546
2780
|
});
|
|
2547
2781
|
}
|
|
2548
2782
|
/**
|
|
2549
|
-
* Return a serialized representation of the experiment that can be used to start subspans in other places.
|
|
2783
|
+
* Return a serialized representation of the experiment that can be used to start subspans in other places.
|
|
2784
|
+
*
|
|
2785
|
+
* See {@link Span.startSpan} for more details.
|
|
2550
2786
|
*/
|
|
2551
2787
|
async export() {
|
|
2552
2788
|
return new import_core.SpanComponentsV3({
|
|
@@ -2561,7 +2797,7 @@ var Experiment = class extends ObjectFetcher {
|
|
|
2561
2797
|
return await this.state.bgLogger().flush();
|
|
2562
2798
|
}
|
|
2563
2799
|
/**
|
|
2564
|
-
* This function is deprecated. You can simply remove it from your code.
|
|
2800
|
+
* @deprecated This function is deprecated. You can simply remove it from your code.
|
|
2565
2801
|
*/
|
|
2566
2802
|
async close() {
|
|
2567
2803
|
console.warn(
|
|
@@ -2703,27 +2939,14 @@ var SpanImpl = class _SpanImpl {
|
|
|
2703
2939
|
event,
|
|
2704
2940
|
internalData
|
|
2705
2941
|
});
|
|
2706
|
-
|
|
2942
|
+
const partialRecord = deepCopyEvent({
|
|
2707
2943
|
id: this.id,
|
|
2708
2944
|
span_id: this.spanId,
|
|
2709
2945
|
root_span_id: this.rootSpanId,
|
|
2710
2946
|
span_parents: this.spanParents,
|
|
2711
2947
|
...serializableInternalData,
|
|
2712
2948
|
[import_core.IS_MERGE_FIELD]: this.isMerge
|
|
2713
|
-
};
|
|
2714
|
-
const serializedPartialRecord = JSON.stringify(partialRecord, (_k, v) => {
|
|
2715
|
-
if (v instanceof _SpanImpl) {
|
|
2716
|
-
return `<span>`;
|
|
2717
|
-
} else if (v instanceof Experiment) {
|
|
2718
|
-
return `<experiment>`;
|
|
2719
|
-
} else if (v instanceof Dataset) {
|
|
2720
|
-
return `<dataset>`;
|
|
2721
|
-
} else if (v instanceof Logger) {
|
|
2722
|
-
return `<logger>`;
|
|
2723
|
-
}
|
|
2724
|
-
return v;
|
|
2725
2949
|
});
|
|
2726
|
-
partialRecord = JSON.parse(serializedPartialRecord);
|
|
2727
2950
|
if (partialRecord.metrics?.end) {
|
|
2728
2951
|
this.loggedEndTime = partialRecord.metrics?.end;
|
|
2729
2952
|
}
|
|
@@ -2958,15 +3181,17 @@ var Dataset = class extends ObjectFetcher {
|
|
|
2958
3181
|
}) {
|
|
2959
3182
|
this.validateEvent({ metadata, expected, output, tags });
|
|
2960
3183
|
const rowId = id || (0, import_uuid.v4)();
|
|
2961
|
-
const args = this.createArgs(
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
3184
|
+
const args = this.createArgs(
|
|
3185
|
+
deepCopyEvent({
|
|
3186
|
+
id: rowId,
|
|
3187
|
+
input,
|
|
3188
|
+
expected,
|
|
3189
|
+
metadata,
|
|
3190
|
+
tags,
|
|
3191
|
+
output,
|
|
3192
|
+
isMerge: false
|
|
3193
|
+
})
|
|
3194
|
+
);
|
|
2970
3195
|
this.state.bgLogger().log([args]);
|
|
2971
3196
|
return rowId;
|
|
2972
3197
|
}
|
|
@@ -2991,14 +3216,16 @@ var Dataset = class extends ObjectFetcher {
|
|
|
2991
3216
|
id
|
|
2992
3217
|
}) {
|
|
2993
3218
|
this.validateEvent({ metadata, expected, tags });
|
|
2994
|
-
const args = this.createArgs(
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3219
|
+
const args = this.createArgs(
|
|
3220
|
+
deepCopyEvent({
|
|
3221
|
+
id,
|
|
3222
|
+
input,
|
|
3223
|
+
expected,
|
|
3224
|
+
metadata,
|
|
3225
|
+
tags,
|
|
3226
|
+
isMerge: true
|
|
3227
|
+
})
|
|
3228
|
+
);
|
|
3002
3229
|
this.state.bgLogger().log([args]);
|
|
3003
3230
|
return id;
|
|
3004
3231
|
}
|
|
@@ -3053,7 +3280,7 @@ var Dataset = class extends ObjectFetcher {
|
|
|
3053
3280
|
return await this.state.bgLogger().flush();
|
|
3054
3281
|
}
|
|
3055
3282
|
/**
|
|
3056
|
-
* This function is deprecated. You can simply remove it from your code.
|
|
3283
|
+
* @deprecated This function is deprecated. You can simply remove it from your code.
|
|
3057
3284
|
*/
|
|
3058
3285
|
async close() {
|
|
3059
3286
|
console.warn(
|
|
@@ -3217,6 +3444,7 @@ var Prompt = class {
|
|
|
3217
3444
|
return this.parsedPromptData;
|
|
3218
3445
|
}
|
|
3219
3446
|
};
|
|
3447
|
+
var _exportsForTestingOnly = { extractAttachments, deepCopyEvent };
|
|
3220
3448
|
|
|
3221
3449
|
// src/browser-config.ts
|
|
3222
3450
|
var browserConfigured = false;
|
|
@@ -3243,6 +3471,7 @@ function configureBrowser() {
|
|
|
3243
3471
|
// src/exports-browser.ts
|
|
3244
3472
|
var exports_browser_exports = {};
|
|
3245
3473
|
__export(exports_browser_exports, {
|
|
3474
|
+
Attachment: () => Attachment,
|
|
3246
3475
|
BraintrustState: () => BraintrustState,
|
|
3247
3476
|
BraintrustStream: () => BraintrustStream,
|
|
3248
3477
|
Dataset: () => Dataset,
|
|
@@ -3256,6 +3485,7 @@ __export(exports_browser_exports, {
|
|
|
3256
3485
|
ReadonlyExperiment: () => ReadonlyExperiment,
|
|
3257
3486
|
SpanImpl: () => SpanImpl,
|
|
3258
3487
|
X_CACHED_HEADER: () => X_CACHED_HEADER,
|
|
3488
|
+
_exportsForTestingOnly: () => _exportsForTestingOnly,
|
|
3259
3489
|
_internalGetGlobalState: () => _internalGetGlobalState,
|
|
3260
3490
|
_internalSetInitialState: () => _internalSetInitialState,
|
|
3261
3491
|
braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
|
|
@@ -3304,7 +3534,7 @@ async function invoke(args) {
|
|
|
3304
3534
|
apiKey,
|
|
3305
3535
|
appUrl,
|
|
3306
3536
|
forceLogin,
|
|
3307
|
-
fetch,
|
|
3537
|
+
fetch: fetch2,
|
|
3308
3538
|
input,
|
|
3309
3539
|
messages,
|
|
3310
3540
|
parent: parentArg,
|
|
@@ -3320,7 +3550,7 @@ async function invoke(args) {
|
|
|
3320
3550
|
apiKey,
|
|
3321
3551
|
appUrl,
|
|
3322
3552
|
forceLogin,
|
|
3323
|
-
fetch
|
|
3553
|
+
fetch: fetch2
|
|
3324
3554
|
});
|
|
3325
3555
|
const parent = parentArg ? typeof parentArg === "string" ? parentArg : await parentArg.export() : await getSpanParentObject().export();
|
|
3326
3556
|
const functionId = import_typespecs3.functionIdSchema.safeParse({
|
|
@@ -3748,6 +3978,7 @@ configureBrowser();
|
|
|
3748
3978
|
var browser_default = exports_browser_exports;
|
|
3749
3979
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3750
3980
|
0 && (module.exports = {
|
|
3981
|
+
Attachment,
|
|
3751
3982
|
BraintrustState,
|
|
3752
3983
|
BraintrustStream,
|
|
3753
3984
|
Dataset,
|
|
@@ -3761,6 +3992,7 @@ var browser_default = exports_browser_exports;
|
|
|
3761
3992
|
ReadonlyExperiment,
|
|
3762
3993
|
SpanImpl,
|
|
3763
3994
|
X_CACHED_HEADER,
|
|
3995
|
+
_exportsForTestingOnly,
|
|
3764
3996
|
_internalGetGlobalState,
|
|
3765
3997
|
_internalSetInitialState,
|
|
3766
3998
|
braintrustStreamChunkSchema,
|