langsmith 0.3.41 → 0.3.42
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/client.cjs +79 -29
- package/dist/client.d.ts +21 -2
- package/dist/client.js +79 -29
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run_trees.cjs +55 -5
- package/dist/run_trees.d.ts +11 -2
- package/dist/run_trees.js +55 -5
- package/dist/utils/error.cjs +22 -1
- package/dist/utils/error.d.ts +5 -0
- package/dist/utils/error.js +19 -0
- package/package.json +1 -1
package/dist/client.cjs
CHANGED
|
@@ -152,6 +152,8 @@ class AutoBatchQueue {
|
|
|
152
152
|
action: item.action,
|
|
153
153
|
payload: item.item,
|
|
154
154
|
otelContext: item.otelContext,
|
|
155
|
+
apiKey: item.apiKey,
|
|
156
|
+
apiUrl: item.apiUrl,
|
|
155
157
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
156
158
|
itemPromiseResolve: itemPromiseResolve,
|
|
157
159
|
itemPromise,
|
|
@@ -189,6 +191,8 @@ class AutoBatchQueue {
|
|
|
189
191
|
action: it.action,
|
|
190
192
|
item: it.payload,
|
|
191
193
|
otelContext: it.otelContext,
|
|
194
|
+
apiKey: it.apiKey,
|
|
195
|
+
apiUrl: it.apiUrl,
|
|
192
196
|
})),
|
|
193
197
|
() => popped.forEach((it) => it.itemPromiseResolve()),
|
|
194
198
|
];
|
|
@@ -451,6 +455,11 @@ class Client {
|
|
|
451
455
|
}
|
|
452
456
|
return headers;
|
|
453
457
|
}
|
|
458
|
+
_getPlatformEndpointPath(path) {
|
|
459
|
+
// Check if apiUrl already ends with /v1 or /v1/ to avoid double /v1/v1/ paths
|
|
460
|
+
const needsV1Prefix = this.apiUrl.slice(-3) !== "/v1" && this.apiUrl.slice(-4) !== "/v1/";
|
|
461
|
+
return needsV1Prefix ? `/v1/platform/${path}` : `/platform/${path}`;
|
|
462
|
+
}
|
|
454
463
|
async processInputs(inputs) {
|
|
455
464
|
if (this.hideInputs === false) {
|
|
456
465
|
return inputs;
|
|
@@ -623,14 +632,33 @@ class Client {
|
|
|
623
632
|
done();
|
|
624
633
|
break;
|
|
625
634
|
}
|
|
626
|
-
const
|
|
627
|
-
|
|
635
|
+
const batchesByDestination = batch.reduce((acc, item) => {
|
|
636
|
+
const apiUrl = item.apiUrl ?? this.apiUrl;
|
|
637
|
+
const apiKey = item.apiKey ?? this.apiKey;
|
|
638
|
+
const isDefault = item.apiKey === this.apiKey && item.apiUrl === this.apiUrl;
|
|
639
|
+
const batchKey = isDefault ? "default" : `${apiUrl}|${apiKey}`;
|
|
640
|
+
if (!acc[batchKey]) {
|
|
641
|
+
acc[batchKey] = [];
|
|
642
|
+
}
|
|
643
|
+
acc[batchKey].push(item);
|
|
644
|
+
return acc;
|
|
645
|
+
}, {});
|
|
646
|
+
const batchPromises = [];
|
|
647
|
+
for (const [batchKey, batch] of Object.entries(batchesByDestination)) {
|
|
648
|
+
const batchPromise = this._processBatch(batch, {
|
|
649
|
+
apiUrl: batchKey === "default" ? undefined : batchKey.split("|")[0],
|
|
650
|
+
apiKey: batchKey === "default" ? undefined : batchKey.split("|")[1],
|
|
651
|
+
});
|
|
652
|
+
batchPromises.push(batchPromise);
|
|
653
|
+
}
|
|
654
|
+
// Wait for all batches to complete, then call the overall done callback
|
|
655
|
+
const allBatchesPromise = Promise.all(batchPromises).finally(done);
|
|
656
|
+
promises.push(allBatchesPromise);
|
|
628
657
|
}
|
|
629
658
|
return Promise.all(promises);
|
|
630
659
|
}
|
|
631
|
-
async _processBatch(batch,
|
|
660
|
+
async _processBatch(batch, options) {
|
|
632
661
|
if (!batch.length) {
|
|
633
|
-
done();
|
|
634
662
|
return;
|
|
635
663
|
}
|
|
636
664
|
try {
|
|
@@ -648,19 +676,16 @@ class Client {
|
|
|
648
676
|
};
|
|
649
677
|
const serverInfo = await this._ensureServerInfo();
|
|
650
678
|
if (serverInfo?.batch_ingest_config?.use_multipart_endpoint) {
|
|
651
|
-
await this.multipartIngestRuns(ingestParams);
|
|
679
|
+
await this.multipartIngestRuns(ingestParams, options);
|
|
652
680
|
}
|
|
653
681
|
else {
|
|
654
|
-
await this.batchIngestRuns(ingestParams);
|
|
682
|
+
await this.batchIngestRuns(ingestParams, options);
|
|
655
683
|
}
|
|
656
684
|
}
|
|
657
685
|
}
|
|
658
686
|
catch (e) {
|
|
659
687
|
console.error("Error exporting batch:", e);
|
|
660
688
|
}
|
|
661
|
-
finally {
|
|
662
|
-
done();
|
|
663
|
-
}
|
|
664
689
|
}
|
|
665
690
|
_sendBatchToOTELTranslator(batch) {
|
|
666
691
|
if (this.langSmithToOTELTranslator !== undefined) {
|
|
@@ -774,11 +799,14 @@ class Client {
|
|
|
774
799
|
}
|
|
775
800
|
return undefined;
|
|
776
801
|
}
|
|
777
|
-
async createRun(run) {
|
|
802
|
+
async createRun(run, options) {
|
|
778
803
|
if (!this._filterForSampling([run]).length) {
|
|
779
804
|
return;
|
|
780
805
|
}
|
|
781
|
-
const headers = {
|
|
806
|
+
const headers = {
|
|
807
|
+
...this.headers,
|
|
808
|
+
"Content-Type": "application/json",
|
|
809
|
+
};
|
|
782
810
|
const session_name = run.project_name;
|
|
783
811
|
delete run.project_name;
|
|
784
812
|
const runCreate = await this.prepareRunCreateOrUpdateInputs({
|
|
@@ -794,11 +822,16 @@ class Client {
|
|
|
794
822
|
action: "create",
|
|
795
823
|
item: runCreate,
|
|
796
824
|
otelContext,
|
|
825
|
+
apiKey: options?.apiKey,
|
|
826
|
+
apiUrl: options?.apiUrl,
|
|
797
827
|
}).catch(console.error);
|
|
798
828
|
return;
|
|
799
829
|
}
|
|
800
830
|
const mergedRunCreateParam = mergeRuntimeEnvIntoRunCreate(runCreate);
|
|
801
|
-
|
|
831
|
+
if (options?.apiKey !== undefined) {
|
|
832
|
+
headers["x-api-key"] = options.apiKey;
|
|
833
|
+
}
|
|
834
|
+
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs`, {
|
|
802
835
|
method: "POST",
|
|
803
836
|
headers,
|
|
804
837
|
body: (0, index_js_2.serialize)(mergedRunCreateParam, `Creating run with id: ${mergedRunCreateParam.id}`),
|
|
@@ -811,7 +844,7 @@ class Client {
|
|
|
811
844
|
* Batch ingest/upsert multiple runs in the Langsmith system.
|
|
812
845
|
* @param runs
|
|
813
846
|
*/
|
|
814
|
-
async batchIngestRuns({ runCreates, runUpdates, }) {
|
|
847
|
+
async batchIngestRuns({ runCreates, runUpdates, }, options) {
|
|
815
848
|
if (runCreates === undefined && runUpdates === undefined) {
|
|
816
849
|
return;
|
|
817
850
|
}
|
|
@@ -866,16 +899,19 @@ class Client {
|
|
|
866
899
|
.map((item) => item.id)
|
|
867
900
|
.concat(batchChunks.patch.map((item) => item.id))
|
|
868
901
|
.join(",");
|
|
869
|
-
await this._postBatchIngestRuns((0, index_js_2.serialize)(batchChunks, `Ingesting runs with ids: ${runIds}`));
|
|
902
|
+
await this._postBatchIngestRuns((0, index_js_2.serialize)(batchChunks, `Ingesting runs with ids: ${runIds}`), options);
|
|
870
903
|
}
|
|
871
904
|
}
|
|
872
|
-
async _postBatchIngestRuns(body) {
|
|
905
|
+
async _postBatchIngestRuns(body, options) {
|
|
873
906
|
const headers = {
|
|
874
907
|
...this.headers,
|
|
875
908
|
"Content-Type": "application/json",
|
|
876
909
|
Accept: "application/json",
|
|
877
910
|
};
|
|
878
|
-
|
|
911
|
+
if (options?.apiKey !== undefined) {
|
|
912
|
+
headers["x-api-key"] = options.apiKey;
|
|
913
|
+
}
|
|
914
|
+
const response = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/batch`, {
|
|
879
915
|
method: "POST",
|
|
880
916
|
headers,
|
|
881
917
|
body: body,
|
|
@@ -888,7 +924,7 @@ class Client {
|
|
|
888
924
|
* Batch ingest/upsert multiple runs in the Langsmith system.
|
|
889
925
|
* @param runs
|
|
890
926
|
*/
|
|
891
|
-
async multipartIngestRuns({ runCreates, runUpdates, }) {
|
|
927
|
+
async multipartIngestRuns({ runCreates, runUpdates, }, options) {
|
|
892
928
|
if (runCreates === undefined && runUpdates === undefined) {
|
|
893
929
|
return;
|
|
894
930
|
}
|
|
@@ -1015,7 +1051,7 @@ class Client {
|
|
|
1015
1051
|
accumulatedContext.push(`trace=${payload.trace_id},id=${payload.id}`);
|
|
1016
1052
|
}
|
|
1017
1053
|
}
|
|
1018
|
-
await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "));
|
|
1054
|
+
await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "), options);
|
|
1019
1055
|
}
|
|
1020
1056
|
async _createNodeFetchBody(parts, boundary) {
|
|
1021
1057
|
// Create multipart form data manually using Blobs
|
|
@@ -1080,19 +1116,23 @@ class Client {
|
|
|
1080
1116
|
});
|
|
1081
1117
|
return stream;
|
|
1082
1118
|
}
|
|
1083
|
-
async _sendMultipartRequest(parts, context) {
|
|
1119
|
+
async _sendMultipartRequest(parts, context, options) {
|
|
1084
1120
|
try {
|
|
1085
1121
|
// Create multipart form data boundary
|
|
1086
1122
|
const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
|
|
1087
1123
|
const body = await ((0, fetch_js_1._globalFetchImplementationIsNodeFetch)()
|
|
1088
1124
|
? this._createNodeFetchBody(parts, boundary)
|
|
1089
1125
|
: this._createMultipartStream(parts, boundary));
|
|
1090
|
-
const
|
|
1126
|
+
const headers = {
|
|
1127
|
+
...this.headers,
|
|
1128
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
1129
|
+
};
|
|
1130
|
+
if (options?.apiKey !== undefined) {
|
|
1131
|
+
headers["x-api-key"] = options.apiKey;
|
|
1132
|
+
}
|
|
1133
|
+
const res = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/multipart`, {
|
|
1091
1134
|
method: "POST",
|
|
1092
|
-
headers
|
|
1093
|
-
...this.headers,
|
|
1094
|
-
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
1095
|
-
},
|
|
1135
|
+
headers,
|
|
1096
1136
|
body,
|
|
1097
1137
|
duplex: "half",
|
|
1098
1138
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
@@ -1105,7 +1145,7 @@ class Client {
|
|
|
1105
1145
|
console.warn(`${e.message.trim()}\n\nContext: ${context}`);
|
|
1106
1146
|
}
|
|
1107
1147
|
}
|
|
1108
|
-
async updateRun(runId, run) {
|
|
1148
|
+
async updateRun(runId, run, options) {
|
|
1109
1149
|
(0, _uuid_js_1.assertUuid)(runId);
|
|
1110
1150
|
if (run.inputs) {
|
|
1111
1151
|
run.inputs = await this.processInputs(run.inputs);
|
|
@@ -1132,6 +1172,8 @@ class Client {
|
|
|
1132
1172
|
action: "update",
|
|
1133
1173
|
item: data,
|
|
1134
1174
|
otelContext,
|
|
1175
|
+
apiKey: options?.apiKey,
|
|
1176
|
+
apiUrl: options?.apiUrl,
|
|
1135
1177
|
}).catch(console.error);
|
|
1136
1178
|
return;
|
|
1137
1179
|
}
|
|
@@ -1140,12 +1182,20 @@ class Client {
|
|
|
1140
1182
|
action: "update",
|
|
1141
1183
|
item: data,
|
|
1142
1184
|
otelContext,
|
|
1185
|
+
apiKey: options?.apiKey,
|
|
1186
|
+
apiUrl: options?.apiUrl,
|
|
1143
1187
|
}).catch(console.error);
|
|
1144
1188
|
}
|
|
1145
1189
|
return;
|
|
1146
1190
|
}
|
|
1147
|
-
const headers = {
|
|
1148
|
-
|
|
1191
|
+
const headers = {
|
|
1192
|
+
...this.headers,
|
|
1193
|
+
"Content-Type": "application/json",
|
|
1194
|
+
};
|
|
1195
|
+
if (options?.apiKey !== undefined) {
|
|
1196
|
+
headers["x-api-key"] = options.apiKey;
|
|
1197
|
+
}
|
|
1198
|
+
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/${runId}`, {
|
|
1149
1199
|
method: "PATCH",
|
|
1150
1200
|
headers,
|
|
1151
1201
|
body: (0, index_js_2.serialize)(run, `Serializing payload to update run with id: ${runId}`),
|
|
@@ -3190,7 +3240,7 @@ class Client {
|
|
|
3190
3240
|
}
|
|
3191
3241
|
}
|
|
3192
3242
|
const datasetIdToUse = datasetId ?? updates[0]?.dataset_id;
|
|
3193
|
-
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}
|
|
3243
|
+
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetIdToUse}/examples`)}`, {
|
|
3194
3244
|
method: "PATCH",
|
|
3195
3245
|
headers: this.headers,
|
|
3196
3246
|
body: formData,
|
|
@@ -3268,7 +3318,7 @@ class Client {
|
|
|
3268
3318
|
}
|
|
3269
3319
|
}
|
|
3270
3320
|
}
|
|
3271
|
-
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}
|
|
3321
|
+
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetId}/examples`)}`, {
|
|
3272
3322
|
method: "POST",
|
|
3273
3323
|
headers: this.headers,
|
|
3274
3324
|
body: formData,
|
package/dist/client.d.ts
CHANGED
|
@@ -242,6 +242,8 @@ type AutoBatchQueueItem = {
|
|
|
242
242
|
action: "create" | "update";
|
|
243
243
|
item: RunCreate | RunUpdate;
|
|
244
244
|
otelContext?: OTELContext;
|
|
245
|
+
apiKey?: string;
|
|
246
|
+
apiUrl?: string;
|
|
245
247
|
};
|
|
246
248
|
type Thread = {
|
|
247
249
|
filter: string;
|
|
@@ -267,6 +269,8 @@ export declare class AutoBatchQueue {
|
|
|
267
269
|
itemPromiseResolve: () => void;
|
|
268
270
|
itemPromise: Promise<void>;
|
|
269
271
|
size: number;
|
|
272
|
+
apiKey?: string;
|
|
273
|
+
apiUrl?: string;
|
|
270
274
|
}[];
|
|
271
275
|
sizeBytes: number;
|
|
272
276
|
peek(): {
|
|
@@ -276,6 +280,8 @@ export declare class AutoBatchQueue {
|
|
|
276
280
|
itemPromiseResolve: () => void;
|
|
277
281
|
itemPromise: Promise<void>;
|
|
278
282
|
size: number;
|
|
283
|
+
apiKey?: string;
|
|
284
|
+
apiUrl?: string;
|
|
279
285
|
};
|
|
280
286
|
push(item: AutoBatchQueueItem): Promise<void>;
|
|
281
287
|
pop(upToSizeBytes: number): [AutoBatchQueueItem[], () => void];
|
|
@@ -317,6 +323,7 @@ export declare class Client implements LangSmithTracingClientInterface {
|
|
|
317
323
|
};
|
|
318
324
|
getHostUrl(): string;
|
|
319
325
|
private get headers();
|
|
326
|
+
private _getPlatformEndpointPath;
|
|
320
327
|
private processInputs;
|
|
321
328
|
private processOutputs;
|
|
322
329
|
private prepareRunCreateOrUpdateInputs;
|
|
@@ -340,7 +347,10 @@ export declare class Client implements LangSmithTracingClientInterface {
|
|
|
340
347
|
*/
|
|
341
348
|
flush(): Promise<void>;
|
|
342
349
|
private _cloneCurrentOTELContext;
|
|
343
|
-
createRun(run: CreateRunParams
|
|
350
|
+
createRun(run: CreateRunParams, options?: {
|
|
351
|
+
apiKey?: string;
|
|
352
|
+
apiUrl?: string;
|
|
353
|
+
}): Promise<void>;
|
|
344
354
|
/**
|
|
345
355
|
* Batch ingest/upsert multiple runs in the Langsmith system.
|
|
346
356
|
* @param runs
|
|
@@ -348,6 +358,9 @@ export declare class Client implements LangSmithTracingClientInterface {
|
|
|
348
358
|
batchIngestRuns({ runCreates, runUpdates, }: {
|
|
349
359
|
runCreates?: RunCreate[];
|
|
350
360
|
runUpdates?: RunUpdate[];
|
|
361
|
+
}, options?: {
|
|
362
|
+
apiKey?: string;
|
|
363
|
+
apiUrl?: string;
|
|
351
364
|
}): Promise<void>;
|
|
352
365
|
private _postBatchIngestRuns;
|
|
353
366
|
/**
|
|
@@ -357,11 +370,17 @@ export declare class Client implements LangSmithTracingClientInterface {
|
|
|
357
370
|
multipartIngestRuns({ runCreates, runUpdates, }: {
|
|
358
371
|
runCreates?: RunCreate[];
|
|
359
372
|
runUpdates?: RunUpdate[];
|
|
373
|
+
}, options?: {
|
|
374
|
+
apiKey?: string;
|
|
375
|
+
apiUrl?: string;
|
|
360
376
|
}): Promise<void>;
|
|
361
377
|
private _createNodeFetchBody;
|
|
362
378
|
private _createMultipartStream;
|
|
363
379
|
private _sendMultipartRequest;
|
|
364
|
-
updateRun(runId: string, run: RunUpdate
|
|
380
|
+
updateRun(runId: string, run: RunUpdate, options?: {
|
|
381
|
+
apiKey?: string;
|
|
382
|
+
apiUrl?: string;
|
|
383
|
+
}): Promise<void>;
|
|
365
384
|
readRun(runId: string, { loadChildRuns }?: {
|
|
366
385
|
loadChildRuns: boolean;
|
|
367
386
|
}): Promise<Run>;
|
package/dist/client.js
CHANGED
|
@@ -115,6 +115,8 @@ export class AutoBatchQueue {
|
|
|
115
115
|
action: item.action,
|
|
116
116
|
payload: item.item,
|
|
117
117
|
otelContext: item.otelContext,
|
|
118
|
+
apiKey: item.apiKey,
|
|
119
|
+
apiUrl: item.apiUrl,
|
|
118
120
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
119
121
|
itemPromiseResolve: itemPromiseResolve,
|
|
120
122
|
itemPromise,
|
|
@@ -152,6 +154,8 @@ export class AutoBatchQueue {
|
|
|
152
154
|
action: it.action,
|
|
153
155
|
item: it.payload,
|
|
154
156
|
otelContext: it.otelContext,
|
|
157
|
+
apiKey: it.apiKey,
|
|
158
|
+
apiUrl: it.apiUrl,
|
|
155
159
|
})),
|
|
156
160
|
() => popped.forEach((it) => it.itemPromiseResolve()),
|
|
157
161
|
];
|
|
@@ -413,6 +417,11 @@ export class Client {
|
|
|
413
417
|
}
|
|
414
418
|
return headers;
|
|
415
419
|
}
|
|
420
|
+
_getPlatformEndpointPath(path) {
|
|
421
|
+
// Check if apiUrl already ends with /v1 or /v1/ to avoid double /v1/v1/ paths
|
|
422
|
+
const needsV1Prefix = this.apiUrl.slice(-3) !== "/v1" && this.apiUrl.slice(-4) !== "/v1/";
|
|
423
|
+
return needsV1Prefix ? `/v1/platform/${path}` : `/platform/${path}`;
|
|
424
|
+
}
|
|
416
425
|
async processInputs(inputs) {
|
|
417
426
|
if (this.hideInputs === false) {
|
|
418
427
|
return inputs;
|
|
@@ -585,14 +594,33 @@ export class Client {
|
|
|
585
594
|
done();
|
|
586
595
|
break;
|
|
587
596
|
}
|
|
588
|
-
const
|
|
589
|
-
|
|
597
|
+
const batchesByDestination = batch.reduce((acc, item) => {
|
|
598
|
+
const apiUrl = item.apiUrl ?? this.apiUrl;
|
|
599
|
+
const apiKey = item.apiKey ?? this.apiKey;
|
|
600
|
+
const isDefault = item.apiKey === this.apiKey && item.apiUrl === this.apiUrl;
|
|
601
|
+
const batchKey = isDefault ? "default" : `${apiUrl}|${apiKey}`;
|
|
602
|
+
if (!acc[batchKey]) {
|
|
603
|
+
acc[batchKey] = [];
|
|
604
|
+
}
|
|
605
|
+
acc[batchKey].push(item);
|
|
606
|
+
return acc;
|
|
607
|
+
}, {});
|
|
608
|
+
const batchPromises = [];
|
|
609
|
+
for (const [batchKey, batch] of Object.entries(batchesByDestination)) {
|
|
610
|
+
const batchPromise = this._processBatch(batch, {
|
|
611
|
+
apiUrl: batchKey === "default" ? undefined : batchKey.split("|")[0],
|
|
612
|
+
apiKey: batchKey === "default" ? undefined : batchKey.split("|")[1],
|
|
613
|
+
});
|
|
614
|
+
batchPromises.push(batchPromise);
|
|
615
|
+
}
|
|
616
|
+
// Wait for all batches to complete, then call the overall done callback
|
|
617
|
+
const allBatchesPromise = Promise.all(batchPromises).finally(done);
|
|
618
|
+
promises.push(allBatchesPromise);
|
|
590
619
|
}
|
|
591
620
|
return Promise.all(promises);
|
|
592
621
|
}
|
|
593
|
-
async _processBatch(batch,
|
|
622
|
+
async _processBatch(batch, options) {
|
|
594
623
|
if (!batch.length) {
|
|
595
|
-
done();
|
|
596
624
|
return;
|
|
597
625
|
}
|
|
598
626
|
try {
|
|
@@ -610,19 +638,16 @@ export class Client {
|
|
|
610
638
|
};
|
|
611
639
|
const serverInfo = await this._ensureServerInfo();
|
|
612
640
|
if (serverInfo?.batch_ingest_config?.use_multipart_endpoint) {
|
|
613
|
-
await this.multipartIngestRuns(ingestParams);
|
|
641
|
+
await this.multipartIngestRuns(ingestParams, options);
|
|
614
642
|
}
|
|
615
643
|
else {
|
|
616
|
-
await this.batchIngestRuns(ingestParams);
|
|
644
|
+
await this.batchIngestRuns(ingestParams, options);
|
|
617
645
|
}
|
|
618
646
|
}
|
|
619
647
|
}
|
|
620
648
|
catch (e) {
|
|
621
649
|
console.error("Error exporting batch:", e);
|
|
622
650
|
}
|
|
623
|
-
finally {
|
|
624
|
-
done();
|
|
625
|
-
}
|
|
626
651
|
}
|
|
627
652
|
_sendBatchToOTELTranslator(batch) {
|
|
628
653
|
if (this.langSmithToOTELTranslator !== undefined) {
|
|
@@ -736,11 +761,14 @@ export class Client {
|
|
|
736
761
|
}
|
|
737
762
|
return undefined;
|
|
738
763
|
}
|
|
739
|
-
async createRun(run) {
|
|
764
|
+
async createRun(run, options) {
|
|
740
765
|
if (!this._filterForSampling([run]).length) {
|
|
741
766
|
return;
|
|
742
767
|
}
|
|
743
|
-
const headers = {
|
|
768
|
+
const headers = {
|
|
769
|
+
...this.headers,
|
|
770
|
+
"Content-Type": "application/json",
|
|
771
|
+
};
|
|
744
772
|
const session_name = run.project_name;
|
|
745
773
|
delete run.project_name;
|
|
746
774
|
const runCreate = await this.prepareRunCreateOrUpdateInputs({
|
|
@@ -756,11 +784,16 @@ export class Client {
|
|
|
756
784
|
action: "create",
|
|
757
785
|
item: runCreate,
|
|
758
786
|
otelContext,
|
|
787
|
+
apiKey: options?.apiKey,
|
|
788
|
+
apiUrl: options?.apiUrl,
|
|
759
789
|
}).catch(console.error);
|
|
760
790
|
return;
|
|
761
791
|
}
|
|
762
792
|
const mergedRunCreateParam = mergeRuntimeEnvIntoRunCreate(runCreate);
|
|
763
|
-
|
|
793
|
+
if (options?.apiKey !== undefined) {
|
|
794
|
+
headers["x-api-key"] = options.apiKey;
|
|
795
|
+
}
|
|
796
|
+
const response = await this.caller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs`, {
|
|
764
797
|
method: "POST",
|
|
765
798
|
headers,
|
|
766
799
|
body: serializePayloadForTracing(mergedRunCreateParam, `Creating run with id: ${mergedRunCreateParam.id}`),
|
|
@@ -773,7 +806,7 @@ export class Client {
|
|
|
773
806
|
* Batch ingest/upsert multiple runs in the Langsmith system.
|
|
774
807
|
* @param runs
|
|
775
808
|
*/
|
|
776
|
-
async batchIngestRuns({ runCreates, runUpdates, }) {
|
|
809
|
+
async batchIngestRuns({ runCreates, runUpdates, }, options) {
|
|
777
810
|
if (runCreates === undefined && runUpdates === undefined) {
|
|
778
811
|
return;
|
|
779
812
|
}
|
|
@@ -828,16 +861,19 @@ export class Client {
|
|
|
828
861
|
.map((item) => item.id)
|
|
829
862
|
.concat(batchChunks.patch.map((item) => item.id))
|
|
830
863
|
.join(",");
|
|
831
|
-
await this._postBatchIngestRuns(serializePayloadForTracing(batchChunks, `Ingesting runs with ids: ${runIds}`));
|
|
864
|
+
await this._postBatchIngestRuns(serializePayloadForTracing(batchChunks, `Ingesting runs with ids: ${runIds}`), options);
|
|
832
865
|
}
|
|
833
866
|
}
|
|
834
|
-
async _postBatchIngestRuns(body) {
|
|
867
|
+
async _postBatchIngestRuns(body, options) {
|
|
835
868
|
const headers = {
|
|
836
869
|
...this.headers,
|
|
837
870
|
"Content-Type": "application/json",
|
|
838
871
|
Accept: "application/json",
|
|
839
872
|
};
|
|
840
|
-
|
|
873
|
+
if (options?.apiKey !== undefined) {
|
|
874
|
+
headers["x-api-key"] = options.apiKey;
|
|
875
|
+
}
|
|
876
|
+
const response = await this.batchIngestCaller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/batch`, {
|
|
841
877
|
method: "POST",
|
|
842
878
|
headers,
|
|
843
879
|
body: body,
|
|
@@ -850,7 +886,7 @@ export class Client {
|
|
|
850
886
|
* Batch ingest/upsert multiple runs in the Langsmith system.
|
|
851
887
|
* @param runs
|
|
852
888
|
*/
|
|
853
|
-
async multipartIngestRuns({ runCreates, runUpdates, }) {
|
|
889
|
+
async multipartIngestRuns({ runCreates, runUpdates, }, options) {
|
|
854
890
|
if (runCreates === undefined && runUpdates === undefined) {
|
|
855
891
|
return;
|
|
856
892
|
}
|
|
@@ -977,7 +1013,7 @@ export class Client {
|
|
|
977
1013
|
accumulatedContext.push(`trace=${payload.trace_id},id=${payload.id}`);
|
|
978
1014
|
}
|
|
979
1015
|
}
|
|
980
|
-
await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "));
|
|
1016
|
+
await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "), options);
|
|
981
1017
|
}
|
|
982
1018
|
async _createNodeFetchBody(parts, boundary) {
|
|
983
1019
|
// Create multipart form data manually using Blobs
|
|
@@ -1042,19 +1078,23 @@ export class Client {
|
|
|
1042
1078
|
});
|
|
1043
1079
|
return stream;
|
|
1044
1080
|
}
|
|
1045
|
-
async _sendMultipartRequest(parts, context) {
|
|
1081
|
+
async _sendMultipartRequest(parts, context, options) {
|
|
1046
1082
|
try {
|
|
1047
1083
|
// Create multipart form data boundary
|
|
1048
1084
|
const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
|
|
1049
1085
|
const body = await (_globalFetchImplementationIsNodeFetch()
|
|
1050
1086
|
? this._createNodeFetchBody(parts, boundary)
|
|
1051
1087
|
: this._createMultipartStream(parts, boundary));
|
|
1052
|
-
const
|
|
1088
|
+
const headers = {
|
|
1089
|
+
...this.headers,
|
|
1090
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
1091
|
+
};
|
|
1092
|
+
if (options?.apiKey !== undefined) {
|
|
1093
|
+
headers["x-api-key"] = options.apiKey;
|
|
1094
|
+
}
|
|
1095
|
+
const res = await this.batchIngestCaller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/multipart`, {
|
|
1053
1096
|
method: "POST",
|
|
1054
|
-
headers
|
|
1055
|
-
...this.headers,
|
|
1056
|
-
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
1057
|
-
},
|
|
1097
|
+
headers,
|
|
1058
1098
|
body,
|
|
1059
1099
|
duplex: "half",
|
|
1060
1100
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
@@ -1067,7 +1107,7 @@ export class Client {
|
|
|
1067
1107
|
console.warn(`${e.message.trim()}\n\nContext: ${context}`);
|
|
1068
1108
|
}
|
|
1069
1109
|
}
|
|
1070
|
-
async updateRun(runId, run) {
|
|
1110
|
+
async updateRun(runId, run, options) {
|
|
1071
1111
|
assertUuid(runId);
|
|
1072
1112
|
if (run.inputs) {
|
|
1073
1113
|
run.inputs = await this.processInputs(run.inputs);
|
|
@@ -1094,6 +1134,8 @@ export class Client {
|
|
|
1094
1134
|
action: "update",
|
|
1095
1135
|
item: data,
|
|
1096
1136
|
otelContext,
|
|
1137
|
+
apiKey: options?.apiKey,
|
|
1138
|
+
apiUrl: options?.apiUrl,
|
|
1097
1139
|
}).catch(console.error);
|
|
1098
1140
|
return;
|
|
1099
1141
|
}
|
|
@@ -1102,12 +1144,20 @@ export class Client {
|
|
|
1102
1144
|
action: "update",
|
|
1103
1145
|
item: data,
|
|
1104
1146
|
otelContext,
|
|
1147
|
+
apiKey: options?.apiKey,
|
|
1148
|
+
apiUrl: options?.apiUrl,
|
|
1105
1149
|
}).catch(console.error);
|
|
1106
1150
|
}
|
|
1107
1151
|
return;
|
|
1108
1152
|
}
|
|
1109
|
-
const headers = {
|
|
1110
|
-
|
|
1153
|
+
const headers = {
|
|
1154
|
+
...this.headers,
|
|
1155
|
+
"Content-Type": "application/json",
|
|
1156
|
+
};
|
|
1157
|
+
if (options?.apiKey !== undefined) {
|
|
1158
|
+
headers["x-api-key"] = options.apiKey;
|
|
1159
|
+
}
|
|
1160
|
+
const response = await this.caller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/${runId}`, {
|
|
1111
1161
|
method: "PATCH",
|
|
1112
1162
|
headers,
|
|
1113
1163
|
body: serializePayloadForTracing(run, `Serializing payload to update run with id: ${runId}`),
|
|
@@ -3152,7 +3202,7 @@ export class Client {
|
|
|
3152
3202
|
}
|
|
3153
3203
|
}
|
|
3154
3204
|
const datasetIdToUse = datasetId ?? updates[0]?.dataset_id;
|
|
3155
|
-
const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}
|
|
3205
|
+
const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetIdToUse}/examples`)}`, {
|
|
3156
3206
|
method: "PATCH",
|
|
3157
3207
|
headers: this.headers,
|
|
3158
3208
|
body: formData,
|
|
@@ -3230,7 +3280,7 @@ export class Client {
|
|
|
3230
3280
|
}
|
|
3231
3281
|
}
|
|
3232
3282
|
}
|
|
3233
|
-
const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}
|
|
3283
|
+
const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetId}/examples`)}`, {
|
|
3234
3284
|
method: "POST",
|
|
3235
3285
|
headers: this.headers,
|
|
3236
3286
|
body: formData,
|
package/dist/index.cjs
CHANGED
|
@@ -10,4 +10,4 @@ Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true
|
|
|
10
10
|
var project_js_1 = require("./utils/project.cjs");
|
|
11
11
|
Object.defineProperty(exports, "getDefaultProjectName", { enumerable: true, get: function () { return project_js_1.getDefaultProjectName; } });
|
|
12
12
|
// Update using yarn bump-version
|
|
13
|
-
exports.__version__ = "0.3.
|
|
13
|
+
exports.__version__ = "0.3.42";
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export type { Dataset, Example, TracerSession, Run, Feedback, RetrieverOutput, }
|
|
|
3
3
|
export { RunTree, type RunTreeConfig } from "./run_trees.js";
|
|
4
4
|
export { overrideFetchImplementation } from "./singletons/fetch.js";
|
|
5
5
|
export { getDefaultProjectName } from "./utils/project.js";
|
|
6
|
-
export declare const __version__ = "0.3.
|
|
6
|
+
export declare const __version__ = "0.3.42";
|
package/dist/index.js
CHANGED
|
@@ -3,4 +3,4 @@ export { RunTree } from "./run_trees.js";
|
|
|
3
3
|
export { overrideFetchImplementation } from "./singletons/fetch.js";
|
|
4
4
|
export { getDefaultProjectName } from "./utils/project.js";
|
|
5
5
|
// Update using yarn bump-version
|
|
6
|
-
export const __version__ = "0.3.
|
|
6
|
+
export const __version__ = "0.3.42";
|
package/dist/run_trees.cjs
CHANGED
|
@@ -40,9 +40,11 @@ exports.isRunnableConfigLike = isRunnableConfigLike;
|
|
|
40
40
|
const uuid = __importStar(require("uuid"));
|
|
41
41
|
const client_js_1 = require("./client.cjs");
|
|
42
42
|
const env_js_1 = require("./env.cjs");
|
|
43
|
+
const error_js_1 = require("./utils/error.cjs");
|
|
43
44
|
const constants_js_1 = require("./singletons/constants.cjs");
|
|
44
45
|
const env_js_2 = require("./utils/env.cjs");
|
|
45
46
|
const project_js_1 = require("./utils/project.cjs");
|
|
47
|
+
const env_js_3 = require("./utils/env.cjs");
|
|
46
48
|
const warn_js_1 = require("./utils/warn.cjs");
|
|
47
49
|
function stripNonAlphanumeric(input) {
|
|
48
50
|
return input.replace(/[-:.]/g, "");
|
|
@@ -300,6 +302,7 @@ class RunTree {
|
|
|
300
302
|
this.trace_id = this.id;
|
|
301
303
|
}
|
|
302
304
|
}
|
|
305
|
+
this.replicas = _ensureWriteReplicas(this.replicas);
|
|
303
306
|
this.execution_order ??= 1;
|
|
304
307
|
this.child_execution_order ??= 1;
|
|
305
308
|
if (!this.dotted_order) {
|
|
@@ -503,9 +506,12 @@ class RunTree {
|
|
|
503
506
|
try {
|
|
504
507
|
const runtimeEnv = (0, env_js_2.getRuntimeEnvironment)();
|
|
505
508
|
if (this.replicas && this.replicas.length > 0) {
|
|
506
|
-
for (const
|
|
507
|
-
const runCreate = this._remapForProject(projectName, runtimeEnv, true);
|
|
508
|
-
await this.client.createRun(runCreate
|
|
509
|
+
for (const { projectName, apiKey, apiUrl } of this.replicas) {
|
|
510
|
+
const runCreate = this._remapForProject(projectName ?? this.project_name, runtimeEnv, true);
|
|
511
|
+
await this.client.createRun(runCreate, {
|
|
512
|
+
apiKey,
|
|
513
|
+
apiUrl,
|
|
514
|
+
});
|
|
509
515
|
}
|
|
510
516
|
}
|
|
511
517
|
else {
|
|
@@ -525,8 +531,8 @@ class RunTree {
|
|
|
525
531
|
}
|
|
526
532
|
async patchRun() {
|
|
527
533
|
if (this.replicas && this.replicas.length > 0) {
|
|
528
|
-
for (const
|
|
529
|
-
const runData = this._remapForProject(projectName);
|
|
534
|
+
for (const { projectName, apiKey, apiUrl, updates } of this.replicas) {
|
|
535
|
+
const runData = this._remapForProject(projectName ?? this.project_name);
|
|
530
536
|
await this.client.updateRun(runData.id, {
|
|
531
537
|
inputs: runData.inputs,
|
|
532
538
|
outputs: runData.outputs,
|
|
@@ -542,6 +548,9 @@ class RunTree {
|
|
|
542
548
|
extra: runData.extra,
|
|
543
549
|
attachments: this.attachments,
|
|
544
550
|
...updates,
|
|
551
|
+
}, {
|
|
552
|
+
apiKey,
|
|
553
|
+
apiUrl,
|
|
545
554
|
});
|
|
546
555
|
}
|
|
547
556
|
}
|
|
@@ -742,3 +751,44 @@ function _parseDottedOrder(dottedOrder) {
|
|
|
742
751
|
return [timestamp, uuidStr];
|
|
743
752
|
});
|
|
744
753
|
}
|
|
754
|
+
function _getWriteReplicasFromEnv() {
|
|
755
|
+
const envVar = (0, env_js_2.getEnvironmentVariable)("LANGSMITH_RUNS_ENDPOINTS");
|
|
756
|
+
if (!envVar)
|
|
757
|
+
return [];
|
|
758
|
+
try {
|
|
759
|
+
const parsed = JSON.parse(envVar);
|
|
760
|
+
_checkEndpointEnvUnset(parsed);
|
|
761
|
+
return Object.entries(parsed).map(([url, key]) => ({
|
|
762
|
+
apiUrl: url.replace(/\/$/, ""),
|
|
763
|
+
apiKey: key,
|
|
764
|
+
}));
|
|
765
|
+
}
|
|
766
|
+
catch (e) {
|
|
767
|
+
if ((0, error_js_1.isConflictingEndpointsError)(e)) {
|
|
768
|
+
throw e;
|
|
769
|
+
}
|
|
770
|
+
console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON mapping of url->apiKey");
|
|
771
|
+
return [];
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function _ensureWriteReplicas(replicas) {
|
|
775
|
+
// If null -> fetch from env
|
|
776
|
+
if (replicas) {
|
|
777
|
+
return replicas.map((replica) => {
|
|
778
|
+
if (Array.isArray(replica)) {
|
|
779
|
+
return {
|
|
780
|
+
projectName: replica[0],
|
|
781
|
+
update: replica[1],
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
return replica;
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
return _getWriteReplicasFromEnv();
|
|
788
|
+
}
|
|
789
|
+
function _checkEndpointEnvUnset(parsed) {
|
|
790
|
+
if (Object.keys(parsed).length > 0 &&
|
|
791
|
+
(0, env_js_3.getLangSmithEnvironmentVariable)("ENDPOINT")) {
|
|
792
|
+
throw new error_js_1.ConflictingEndpointsError();
|
|
793
|
+
}
|
|
794
|
+
}
|
package/dist/run_trees.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface RunTreeConfig {
|
|
|
27
27
|
trace_id?: string;
|
|
28
28
|
dotted_order?: string;
|
|
29
29
|
attachments?: Attachments;
|
|
30
|
-
replicas?: [
|
|
30
|
+
replicas?: Replica[];
|
|
31
31
|
}
|
|
32
32
|
export interface RunnableConfigLike {
|
|
33
33
|
/**
|
|
@@ -50,6 +50,15 @@ interface HeadersLike {
|
|
|
50
50
|
get(name: string): string | null;
|
|
51
51
|
set(name: string, value: string): void;
|
|
52
52
|
}
|
|
53
|
+
type ProjectReplica = [string, KVMap | undefined];
|
|
54
|
+
type WriteReplica = {
|
|
55
|
+
apiUrl?: string;
|
|
56
|
+
apiKey?: string;
|
|
57
|
+
projectName?: string;
|
|
58
|
+
updates?: KVMap | undefined;
|
|
59
|
+
fromEnv?: boolean;
|
|
60
|
+
};
|
|
61
|
+
type Replica = ProjectReplica | WriteReplica;
|
|
53
62
|
export declare class RunTree implements BaseRun {
|
|
54
63
|
private static sharedClient;
|
|
55
64
|
id: string;
|
|
@@ -82,7 +91,7 @@ export declare class RunTree implements BaseRun {
|
|
|
82
91
|
/**
|
|
83
92
|
* Projects to replicate this run to with optional updates.
|
|
84
93
|
*/
|
|
85
|
-
replicas?: [
|
|
94
|
+
replicas?: WriteReplica[];
|
|
86
95
|
constructor(originalConfig: RunTreeConfig | RunTree);
|
|
87
96
|
set metadata(metadata: KVMap);
|
|
88
97
|
get metadata(): KVMap;
|
package/dist/run_trees.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as uuid from "uuid";
|
|
2
2
|
import { Client } from "./client.js";
|
|
3
3
|
import { isTracingEnabled } from "./env.js";
|
|
4
|
+
import { isConflictingEndpointsError, ConflictingEndpointsError, } from "./utils/error.js";
|
|
4
5
|
import { _LC_CONTEXT_VARIABLES_KEY } from "./singletons/constants.js";
|
|
5
6
|
import { getEnvironmentVariable, getRuntimeEnvironment, } from "./utils/env.js";
|
|
6
7
|
import { getDefaultProjectName } from "./utils/project.js";
|
|
8
|
+
import { getLangSmithEnvironmentVariable } from "./utils/env.js";
|
|
7
9
|
import { warnOnce } from "./utils/warn.js";
|
|
8
10
|
function stripNonAlphanumeric(input) {
|
|
9
11
|
return input.replace(/[-:.]/g, "");
|
|
@@ -261,6 +263,7 @@ export class RunTree {
|
|
|
261
263
|
this.trace_id = this.id;
|
|
262
264
|
}
|
|
263
265
|
}
|
|
266
|
+
this.replicas = _ensureWriteReplicas(this.replicas);
|
|
264
267
|
this.execution_order ??= 1;
|
|
265
268
|
this.child_execution_order ??= 1;
|
|
266
269
|
if (!this.dotted_order) {
|
|
@@ -464,9 +467,12 @@ export class RunTree {
|
|
|
464
467
|
try {
|
|
465
468
|
const runtimeEnv = getRuntimeEnvironment();
|
|
466
469
|
if (this.replicas && this.replicas.length > 0) {
|
|
467
|
-
for (const
|
|
468
|
-
const runCreate = this._remapForProject(projectName, runtimeEnv, true);
|
|
469
|
-
await this.client.createRun(runCreate
|
|
470
|
+
for (const { projectName, apiKey, apiUrl } of this.replicas) {
|
|
471
|
+
const runCreate = this._remapForProject(projectName ?? this.project_name, runtimeEnv, true);
|
|
472
|
+
await this.client.createRun(runCreate, {
|
|
473
|
+
apiKey,
|
|
474
|
+
apiUrl,
|
|
475
|
+
});
|
|
470
476
|
}
|
|
471
477
|
}
|
|
472
478
|
else {
|
|
@@ -486,8 +492,8 @@ export class RunTree {
|
|
|
486
492
|
}
|
|
487
493
|
async patchRun() {
|
|
488
494
|
if (this.replicas && this.replicas.length > 0) {
|
|
489
|
-
for (const
|
|
490
|
-
const runData = this._remapForProject(projectName);
|
|
495
|
+
for (const { projectName, apiKey, apiUrl, updates } of this.replicas) {
|
|
496
|
+
const runData = this._remapForProject(projectName ?? this.project_name);
|
|
491
497
|
await this.client.updateRun(runData.id, {
|
|
492
498
|
inputs: runData.inputs,
|
|
493
499
|
outputs: runData.outputs,
|
|
@@ -503,6 +509,9 @@ export class RunTree {
|
|
|
503
509
|
extra: runData.extra,
|
|
504
510
|
attachments: this.attachments,
|
|
505
511
|
...updates,
|
|
512
|
+
}, {
|
|
513
|
+
apiKey,
|
|
514
|
+
apiUrl,
|
|
506
515
|
});
|
|
507
516
|
}
|
|
508
517
|
}
|
|
@@ -702,3 +711,44 @@ function _parseDottedOrder(dottedOrder) {
|
|
|
702
711
|
return [timestamp, uuidStr];
|
|
703
712
|
});
|
|
704
713
|
}
|
|
714
|
+
function _getWriteReplicasFromEnv() {
|
|
715
|
+
const envVar = getEnvironmentVariable("LANGSMITH_RUNS_ENDPOINTS");
|
|
716
|
+
if (!envVar)
|
|
717
|
+
return [];
|
|
718
|
+
try {
|
|
719
|
+
const parsed = JSON.parse(envVar);
|
|
720
|
+
_checkEndpointEnvUnset(parsed);
|
|
721
|
+
return Object.entries(parsed).map(([url, key]) => ({
|
|
722
|
+
apiUrl: url.replace(/\/$/, ""),
|
|
723
|
+
apiKey: key,
|
|
724
|
+
}));
|
|
725
|
+
}
|
|
726
|
+
catch (e) {
|
|
727
|
+
if (isConflictingEndpointsError(e)) {
|
|
728
|
+
throw e;
|
|
729
|
+
}
|
|
730
|
+
console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON mapping of url->apiKey");
|
|
731
|
+
return [];
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
function _ensureWriteReplicas(replicas) {
|
|
735
|
+
// If null -> fetch from env
|
|
736
|
+
if (replicas) {
|
|
737
|
+
return replicas.map((replica) => {
|
|
738
|
+
if (Array.isArray(replica)) {
|
|
739
|
+
return {
|
|
740
|
+
projectName: replica[0],
|
|
741
|
+
update: replica[1],
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
return replica;
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
return _getWriteReplicasFromEnv();
|
|
748
|
+
}
|
|
749
|
+
function _checkEndpointEnvUnset(parsed) {
|
|
750
|
+
if (Object.keys(parsed).length > 0 &&
|
|
751
|
+
getLangSmithEnvironmentVariable("ENDPOINT")) {
|
|
752
|
+
throw new ConflictingEndpointsError();
|
|
753
|
+
}
|
|
754
|
+
}
|
package/dist/utils/error.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LangSmithConflictError = void 0;
|
|
3
|
+
exports.ConflictingEndpointsError = exports.LangSmithConflictError = void 0;
|
|
4
4
|
exports.printErrorStackTrace = printErrorStackTrace;
|
|
5
5
|
exports.raiseForStatus = raiseForStatus;
|
|
6
|
+
exports.isConflictingEndpointsError = isConflictingEndpointsError;
|
|
6
7
|
function getErrorStackTrace(e) {
|
|
7
8
|
if (typeof e !== "object" || e == null)
|
|
8
9
|
return undefined;
|
|
@@ -96,3 +97,23 @@ async function raiseForStatus(response, context, consume) {
|
|
|
96
97
|
err.status = response.status;
|
|
97
98
|
throw err;
|
|
98
99
|
}
|
|
100
|
+
const ERR_CONFLICTING_ENDPOINTS = "ERR_CONFLICTING_ENDPOINTS";
|
|
101
|
+
class ConflictingEndpointsError extends Error {
|
|
102
|
+
constructor() {
|
|
103
|
+
super("You cannot provide both LANGSMITH_ENDPOINT / LANGCHAIN_ENDPOINT " +
|
|
104
|
+
"and LANGSMITH_RUNS_ENDPOINTS.");
|
|
105
|
+
Object.defineProperty(this, "code", {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
configurable: true,
|
|
108
|
+
writable: true,
|
|
109
|
+
value: ERR_CONFLICTING_ENDPOINTS
|
|
110
|
+
});
|
|
111
|
+
this.name = "ConflictingEndpointsError"; // helpful in logs
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.ConflictingEndpointsError = ConflictingEndpointsError;
|
|
115
|
+
function isConflictingEndpointsError(err) {
|
|
116
|
+
return (typeof err === "object" &&
|
|
117
|
+
err !== null &&
|
|
118
|
+
err.code === ERR_CONFLICTING_ENDPOINTS);
|
|
119
|
+
}
|
package/dist/utils/error.d.ts
CHANGED
|
@@ -43,3 +43,8 @@ export declare class LangSmithConflictError extends Error {
|
|
|
43
43
|
* @throws {Error} For all other non-ok responses
|
|
44
44
|
*/
|
|
45
45
|
export declare function raiseForStatus(response: Response, context: string, consume?: boolean): Promise<void>;
|
|
46
|
+
export declare class ConflictingEndpointsError extends Error {
|
|
47
|
+
readonly code = "ERR_CONFLICTING_ENDPOINTS";
|
|
48
|
+
constructor();
|
|
49
|
+
}
|
|
50
|
+
export declare function isConflictingEndpointsError(err: unknown): err is ConflictingEndpointsError;
|
package/dist/utils/error.js
CHANGED
|
@@ -90,3 +90,22 @@ export async function raiseForStatus(response, context, consume) {
|
|
|
90
90
|
err.status = response.status;
|
|
91
91
|
throw err;
|
|
92
92
|
}
|
|
93
|
+
const ERR_CONFLICTING_ENDPOINTS = "ERR_CONFLICTING_ENDPOINTS";
|
|
94
|
+
export class ConflictingEndpointsError extends Error {
|
|
95
|
+
constructor() {
|
|
96
|
+
super("You cannot provide both LANGSMITH_ENDPOINT / LANGCHAIN_ENDPOINT " +
|
|
97
|
+
"and LANGSMITH_RUNS_ENDPOINTS.");
|
|
98
|
+
Object.defineProperty(this, "code", {
|
|
99
|
+
enumerable: true,
|
|
100
|
+
configurable: true,
|
|
101
|
+
writable: true,
|
|
102
|
+
value: ERR_CONFLICTING_ENDPOINTS
|
|
103
|
+
});
|
|
104
|
+
this.name = "ConflictingEndpointsError"; // helpful in logs
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function isConflictingEndpointsError(err) {
|
|
108
|
+
return (typeof err === "object" &&
|
|
109
|
+
err !== null &&
|
|
110
|
+
err.code === ERR_CONFLICTING_ENDPOINTS);
|
|
111
|
+
}
|