langsmith 0.3.41 → 0.3.43

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 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
  ];
@@ -198,6 +202,7 @@ exports.AutoBatchQueue = AutoBatchQueue;
198
202
  // 20 MB
199
203
  exports.DEFAULT_BATCH_SIZE_LIMIT_BYTES = 20_971_520;
200
204
  const SERVER_INFO_REQUEST_TIMEOUT = 2500;
205
+ const DEFAULT_API_URL = "https://api.smith.langchain.com";
201
206
  class Client {
202
207
  constructor(config = {}) {
203
208
  Object.defineProperty(this, "apiKey", {
@@ -345,6 +350,12 @@ class Client {
345
350
  writable: true,
346
351
  value: void 0
347
352
  });
353
+ Object.defineProperty(this, "multipartStreamingDisabled", {
354
+ enumerable: true,
355
+ configurable: true,
356
+ writable: true,
357
+ value: false
358
+ });
348
359
  Object.defineProperty(this, "debug", {
349
360
  enumerable: true,
350
361
  configurable: true,
@@ -396,8 +407,7 @@ class Client {
396
407
  }
397
408
  static getDefaultClientConfig() {
398
409
  const apiKey = (0, env_js_1.getLangSmithEnvironmentVariable)("API_KEY");
399
- const apiUrl = (0, env_js_1.getLangSmithEnvironmentVariable)("ENDPOINT") ??
400
- "https://api.smith.langchain.com";
410
+ const apiUrl = (0, env_js_1.getLangSmithEnvironmentVariable)("ENDPOINT") ?? DEFAULT_API_URL;
401
411
  const hideInputs = (0, env_js_1.getLangSmithEnvironmentVariable)("HIDE_INPUTS") === "true";
402
412
  const hideOutputs = (0, env_js_1.getLangSmithEnvironmentVariable)("HIDE_OUTPUTS") === "true";
403
413
  return {
@@ -451,6 +461,11 @@ class Client {
451
461
  }
452
462
  return headers;
453
463
  }
464
+ _getPlatformEndpointPath(path) {
465
+ // Check if apiUrl already ends with /v1 or /v1/ to avoid double /v1/v1/ paths
466
+ const needsV1Prefix = this.apiUrl.slice(-3) !== "/v1" && this.apiUrl.slice(-4) !== "/v1/";
467
+ return needsV1Prefix ? `/v1/platform/${path}` : `/platform/${path}`;
468
+ }
454
469
  async processInputs(inputs) {
455
470
  if (this.hideInputs === false) {
456
471
  return inputs;
@@ -623,14 +638,33 @@ class Client {
623
638
  done();
624
639
  break;
625
640
  }
626
- const batchPromise = this._processBatch(batch, done).catch(console.error);
627
- promises.push(batchPromise);
641
+ const batchesByDestination = batch.reduce((acc, item) => {
642
+ const apiUrl = item.apiUrl ?? this.apiUrl;
643
+ const apiKey = item.apiKey ?? this.apiKey;
644
+ const isDefault = item.apiKey === this.apiKey && item.apiUrl === this.apiUrl;
645
+ const batchKey = isDefault ? "default" : `${apiUrl}|${apiKey}`;
646
+ if (!acc[batchKey]) {
647
+ acc[batchKey] = [];
648
+ }
649
+ acc[batchKey].push(item);
650
+ return acc;
651
+ }, {});
652
+ const batchPromises = [];
653
+ for (const [batchKey, batch] of Object.entries(batchesByDestination)) {
654
+ const batchPromise = this._processBatch(batch, {
655
+ apiUrl: batchKey === "default" ? undefined : batchKey.split("|")[0],
656
+ apiKey: batchKey === "default" ? undefined : batchKey.split("|")[1],
657
+ });
658
+ batchPromises.push(batchPromise);
659
+ }
660
+ // Wait for all batches to complete, then call the overall done callback
661
+ const allBatchesPromise = Promise.all(batchPromises).finally(done);
662
+ promises.push(allBatchesPromise);
628
663
  }
629
664
  return Promise.all(promises);
630
665
  }
631
- async _processBatch(batch, done) {
666
+ async _processBatch(batch, options) {
632
667
  if (!batch.length) {
633
- done();
634
668
  return;
635
669
  }
636
670
  try {
@@ -648,19 +682,16 @@ class Client {
648
682
  };
649
683
  const serverInfo = await this._ensureServerInfo();
650
684
  if (serverInfo?.batch_ingest_config?.use_multipart_endpoint) {
651
- await this.multipartIngestRuns(ingestParams);
685
+ await this.multipartIngestRuns(ingestParams, options);
652
686
  }
653
687
  else {
654
- await this.batchIngestRuns(ingestParams);
688
+ await this.batchIngestRuns(ingestParams, options);
655
689
  }
656
690
  }
657
691
  }
658
692
  catch (e) {
659
693
  console.error("Error exporting batch:", e);
660
694
  }
661
- finally {
662
- done();
663
- }
664
695
  }
665
696
  _sendBatchToOTELTranslator(batch) {
666
697
  if (this.langSmithToOTELTranslator !== undefined) {
@@ -774,11 +805,14 @@ class Client {
774
805
  }
775
806
  return undefined;
776
807
  }
777
- async createRun(run) {
808
+ async createRun(run, options) {
778
809
  if (!this._filterForSampling([run]).length) {
779
810
  return;
780
811
  }
781
- const headers = { ...this.headers, "Content-Type": "application/json" };
812
+ const headers = {
813
+ ...this.headers,
814
+ "Content-Type": "application/json",
815
+ };
782
816
  const session_name = run.project_name;
783
817
  delete run.project_name;
784
818
  const runCreate = await this.prepareRunCreateOrUpdateInputs({
@@ -794,11 +828,16 @@ class Client {
794
828
  action: "create",
795
829
  item: runCreate,
796
830
  otelContext,
831
+ apiKey: options?.apiKey,
832
+ apiUrl: options?.apiUrl,
797
833
  }).catch(console.error);
798
834
  return;
799
835
  }
800
836
  const mergedRunCreateParam = mergeRuntimeEnvIntoRunCreate(runCreate);
801
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/runs`, {
837
+ if (options?.apiKey !== undefined) {
838
+ headers["x-api-key"] = options.apiKey;
839
+ }
840
+ const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs`, {
802
841
  method: "POST",
803
842
  headers,
804
843
  body: (0, index_js_2.serialize)(mergedRunCreateParam, `Creating run with id: ${mergedRunCreateParam.id}`),
@@ -811,7 +850,7 @@ class Client {
811
850
  * Batch ingest/upsert multiple runs in the Langsmith system.
812
851
  * @param runs
813
852
  */
814
- async batchIngestRuns({ runCreates, runUpdates, }) {
853
+ async batchIngestRuns({ runCreates, runUpdates, }, options) {
815
854
  if (runCreates === undefined && runUpdates === undefined) {
816
855
  return;
817
856
  }
@@ -866,16 +905,19 @@ class Client {
866
905
  .map((item) => item.id)
867
906
  .concat(batchChunks.patch.map((item) => item.id))
868
907
  .join(",");
869
- await this._postBatchIngestRuns((0, index_js_2.serialize)(batchChunks, `Ingesting runs with ids: ${runIds}`));
908
+ await this._postBatchIngestRuns((0, index_js_2.serialize)(batchChunks, `Ingesting runs with ids: ${runIds}`), options);
870
909
  }
871
910
  }
872
- async _postBatchIngestRuns(body) {
911
+ async _postBatchIngestRuns(body, options) {
873
912
  const headers = {
874
913
  ...this.headers,
875
914
  "Content-Type": "application/json",
876
915
  Accept: "application/json",
877
916
  };
878
- const response = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/runs/batch`, {
917
+ if (options?.apiKey !== undefined) {
918
+ headers["x-api-key"] = options.apiKey;
919
+ }
920
+ const response = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/batch`, {
879
921
  method: "POST",
880
922
  headers,
881
923
  body: body,
@@ -888,7 +930,7 @@ class Client {
888
930
  * Batch ingest/upsert multiple runs in the Langsmith system.
889
931
  * @param runs
890
932
  */
891
- async multipartIngestRuns({ runCreates, runUpdates, }) {
933
+ async multipartIngestRuns({ runCreates, runUpdates, }, options) {
892
934
  if (runCreates === undefined && runUpdates === undefined) {
893
935
  return;
894
936
  }
@@ -1015,7 +1057,7 @@ class Client {
1015
1057
  accumulatedContext.push(`trace=${payload.trace_id},id=${payload.id}`);
1016
1058
  }
1017
1059
  }
1018
- await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "));
1060
+ await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "), options);
1019
1061
  }
1020
1062
  async _createNodeFetchBody(parts, boundary) {
1021
1063
  // Create multipart form data manually using Blobs
@@ -1080,24 +1122,53 @@ class Client {
1080
1122
  });
1081
1123
  return stream;
1082
1124
  }
1083
- async _sendMultipartRequest(parts, context) {
1084
- try {
1085
- // Create multipart form data boundary
1086
- const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
1087
- const body = await ((0, fetch_js_1._globalFetchImplementationIsNodeFetch)()
1088
- ? this._createNodeFetchBody(parts, boundary)
1089
- : this._createMultipartStream(parts, boundary));
1090
- const res = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/runs/multipart`, {
1125
+ async _sendMultipartRequest(parts, context, options) {
1126
+ // Create multipart form data boundary
1127
+ const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
1128
+ const isNodeFetch = (0, fetch_js_1._globalFetchImplementationIsNodeFetch)();
1129
+ const buildBuffered = () => this._createNodeFetchBody(parts, boundary);
1130
+ const buildStream = () => this._createMultipartStream(parts, boundary);
1131
+ const send = async (body) => {
1132
+ const headers = {
1133
+ ...this.headers,
1134
+ "Content-Type": `multipart/form-data; boundary=${boundary}`,
1135
+ };
1136
+ if (options?.apiKey !== undefined) {
1137
+ headers["x-api-key"] = options.apiKey;
1138
+ }
1139
+ return this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/multipart`, {
1091
1140
  method: "POST",
1092
- headers: {
1093
- ...this.headers,
1094
- "Content-Type": `multipart/form-data; boundary=${boundary}`,
1095
- },
1141
+ headers,
1096
1142
  body,
1097
1143
  duplex: "half",
1098
1144
  signal: AbortSignal.timeout(this.timeout_ms),
1099
1145
  ...this.fetchOptions,
1100
1146
  });
1147
+ };
1148
+ try {
1149
+ let res;
1150
+ let streamedAttempt = false;
1151
+ // attempt stream only if not disabled and not using node-fetch
1152
+ if (!isNodeFetch && !this.multipartStreamingDisabled) {
1153
+ streamedAttempt = true;
1154
+ res = await send(await buildStream());
1155
+ }
1156
+ else {
1157
+ res = await send(await buildBuffered());
1158
+ }
1159
+ // if stream fails, fallback to buffered body
1160
+ if ((!this.multipartStreamingDisabled || streamedAttempt) &&
1161
+ res.status === 422 &&
1162
+ (options?.apiUrl ?? this.apiUrl) !== DEFAULT_API_URL) {
1163
+ console.warn(`Streaming multipart upload to ${options?.apiUrl ?? this.apiUrl}/runs/multipart failed. ` +
1164
+ `This usually means the host does not support chunked uploads. ` +
1165
+ `Retrying with a buffered upload for operation "${context}".`);
1166
+ // Disable streaming for future requests
1167
+ this.multipartStreamingDisabled = true;
1168
+ // retry with fully-buffered body
1169
+ res = await send(await buildBuffered());
1170
+ }
1171
+ // raise if still failing
1101
1172
  await (0, error_js_1.raiseForStatus)(res, "ingest multipart runs", true);
1102
1173
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1103
1174
  }
@@ -1105,7 +1176,7 @@ class Client {
1105
1176
  console.warn(`${e.message.trim()}\n\nContext: ${context}`);
1106
1177
  }
1107
1178
  }
1108
- async updateRun(runId, run) {
1179
+ async updateRun(runId, run, options) {
1109
1180
  (0, _uuid_js_1.assertUuid)(runId);
1110
1181
  if (run.inputs) {
1111
1182
  run.inputs = await this.processInputs(run.inputs);
@@ -1132,6 +1203,8 @@ class Client {
1132
1203
  action: "update",
1133
1204
  item: data,
1134
1205
  otelContext,
1206
+ apiKey: options?.apiKey,
1207
+ apiUrl: options?.apiUrl,
1135
1208
  }).catch(console.error);
1136
1209
  return;
1137
1210
  }
@@ -1140,12 +1213,20 @@ class Client {
1140
1213
  action: "update",
1141
1214
  item: data,
1142
1215
  otelContext,
1216
+ apiKey: options?.apiKey,
1217
+ apiUrl: options?.apiUrl,
1143
1218
  }).catch(console.error);
1144
1219
  }
1145
1220
  return;
1146
1221
  }
1147
- const headers = { ...this.headers, "Content-Type": "application/json" };
1148
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/runs/${runId}`, {
1222
+ const headers = {
1223
+ ...this.headers,
1224
+ "Content-Type": "application/json",
1225
+ };
1226
+ if (options?.apiKey !== undefined) {
1227
+ headers["x-api-key"] = options.apiKey;
1228
+ }
1229
+ const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/${runId}`, {
1149
1230
  method: "PATCH",
1150
1231
  headers,
1151
1232
  body: (0, index_js_2.serialize)(run, `Serializing payload to update run with id: ${runId}`),
@@ -3072,7 +3153,7 @@ class Client {
3072
3153
  const settings = await this._getSettings();
3073
3154
  if (options?.isPublic && !settings.tenant_handle) {
3074
3155
  throw new Error(`Cannot create a public prompt without first\n
3075
- creating a LangChain Hub handle.
3156
+ creating a LangChain Hub handle.
3076
3157
  You can add a handle by creating a public prompt at:\n
3077
3158
  https://smith.langchain.com/prompts`);
3078
3159
  }
@@ -3190,7 +3271,7 @@ class Client {
3190
3271
  }
3191
3272
  }
3192
3273
  const datasetIdToUse = datasetId ?? updates[0]?.dataset_id;
3193
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/v1/platform/datasets/${datasetIdToUse}/examples`, {
3274
+ const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetIdToUse}/examples`)}`, {
3194
3275
  method: "PATCH",
3195
3276
  headers: this.headers,
3196
3277
  body: formData,
@@ -3268,7 +3349,7 @@ class Client {
3268
3349
  }
3269
3350
  }
3270
3351
  }
3271
- const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/v1/platform/datasets/${datasetId}/examples`, {
3352
+ const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetId}/examples`)}`, {
3272
3353
  method: "POST",
3273
3354
  headers: this.headers,
3274
3355
  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];
@@ -306,6 +312,7 @@ export declare class Client implements LangSmithTracingClientInterface {
306
312
  private _getServerInfoPromise?;
307
313
  private manualFlushMode;
308
314
  private langSmithToOTELTranslator?;
315
+ private multipartStreamingDisabled;
309
316
  debug: boolean;
310
317
  constructor(config?: ClientConfig);
311
318
  static getDefaultClientConfig(): {
@@ -317,6 +324,7 @@ export declare class Client implements LangSmithTracingClientInterface {
317
324
  };
318
325
  getHostUrl(): string;
319
326
  private get headers();
327
+ private _getPlatformEndpointPath;
320
328
  private processInputs;
321
329
  private processOutputs;
322
330
  private prepareRunCreateOrUpdateInputs;
@@ -340,7 +348,10 @@ export declare class Client implements LangSmithTracingClientInterface {
340
348
  */
341
349
  flush(): Promise<void>;
342
350
  private _cloneCurrentOTELContext;
343
- createRun(run: CreateRunParams): Promise<void>;
351
+ createRun(run: CreateRunParams, options?: {
352
+ apiKey?: string;
353
+ apiUrl?: string;
354
+ }): Promise<void>;
344
355
  /**
345
356
  * Batch ingest/upsert multiple runs in the Langsmith system.
346
357
  * @param runs
@@ -348,6 +359,9 @@ export declare class Client implements LangSmithTracingClientInterface {
348
359
  batchIngestRuns({ runCreates, runUpdates, }: {
349
360
  runCreates?: RunCreate[];
350
361
  runUpdates?: RunUpdate[];
362
+ }, options?: {
363
+ apiKey?: string;
364
+ apiUrl?: string;
351
365
  }): Promise<void>;
352
366
  private _postBatchIngestRuns;
353
367
  /**
@@ -357,11 +371,17 @@ export declare class Client implements LangSmithTracingClientInterface {
357
371
  multipartIngestRuns({ runCreates, runUpdates, }: {
358
372
  runCreates?: RunCreate[];
359
373
  runUpdates?: RunUpdate[];
374
+ }, options?: {
375
+ apiKey?: string;
376
+ apiUrl?: string;
360
377
  }): Promise<void>;
361
378
  private _createNodeFetchBody;
362
379
  private _createMultipartStream;
363
380
  private _sendMultipartRequest;
364
- updateRun(runId: string, run: RunUpdate): Promise<void>;
381
+ updateRun(runId: string, run: RunUpdate, options?: {
382
+ apiKey?: string;
383
+ apiUrl?: string;
384
+ }): Promise<void>;
365
385
  readRun(runId: string, { loadChildRuns }?: {
366
386
  loadChildRuns: boolean;
367
387
  }): 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
  ];
@@ -160,6 +164,7 @@ export class AutoBatchQueue {
160
164
  // 20 MB
161
165
  export const DEFAULT_BATCH_SIZE_LIMIT_BYTES = 20_971_520;
162
166
  const SERVER_INFO_REQUEST_TIMEOUT = 2500;
167
+ const DEFAULT_API_URL = "https://api.smith.langchain.com";
163
168
  export class Client {
164
169
  constructor(config = {}) {
165
170
  Object.defineProperty(this, "apiKey", {
@@ -307,6 +312,12 @@ export class Client {
307
312
  writable: true,
308
313
  value: void 0
309
314
  });
315
+ Object.defineProperty(this, "multipartStreamingDisabled", {
316
+ enumerable: true,
317
+ configurable: true,
318
+ writable: true,
319
+ value: false
320
+ });
310
321
  Object.defineProperty(this, "debug", {
311
322
  enumerable: true,
312
323
  configurable: true,
@@ -358,8 +369,7 @@ export class Client {
358
369
  }
359
370
  static getDefaultClientConfig() {
360
371
  const apiKey = getLangSmithEnvironmentVariable("API_KEY");
361
- const apiUrl = getLangSmithEnvironmentVariable("ENDPOINT") ??
362
- "https://api.smith.langchain.com";
372
+ const apiUrl = getLangSmithEnvironmentVariable("ENDPOINT") ?? DEFAULT_API_URL;
363
373
  const hideInputs = getLangSmithEnvironmentVariable("HIDE_INPUTS") === "true";
364
374
  const hideOutputs = getLangSmithEnvironmentVariable("HIDE_OUTPUTS") === "true";
365
375
  return {
@@ -413,6 +423,11 @@ export class Client {
413
423
  }
414
424
  return headers;
415
425
  }
426
+ _getPlatformEndpointPath(path) {
427
+ // Check if apiUrl already ends with /v1 or /v1/ to avoid double /v1/v1/ paths
428
+ const needsV1Prefix = this.apiUrl.slice(-3) !== "/v1" && this.apiUrl.slice(-4) !== "/v1/";
429
+ return needsV1Prefix ? `/v1/platform/${path}` : `/platform/${path}`;
430
+ }
416
431
  async processInputs(inputs) {
417
432
  if (this.hideInputs === false) {
418
433
  return inputs;
@@ -585,14 +600,33 @@ export class Client {
585
600
  done();
586
601
  break;
587
602
  }
588
- const batchPromise = this._processBatch(batch, done).catch(console.error);
589
- promises.push(batchPromise);
603
+ const batchesByDestination = batch.reduce((acc, item) => {
604
+ const apiUrl = item.apiUrl ?? this.apiUrl;
605
+ const apiKey = item.apiKey ?? this.apiKey;
606
+ const isDefault = item.apiKey === this.apiKey && item.apiUrl === this.apiUrl;
607
+ const batchKey = isDefault ? "default" : `${apiUrl}|${apiKey}`;
608
+ if (!acc[batchKey]) {
609
+ acc[batchKey] = [];
610
+ }
611
+ acc[batchKey].push(item);
612
+ return acc;
613
+ }, {});
614
+ const batchPromises = [];
615
+ for (const [batchKey, batch] of Object.entries(batchesByDestination)) {
616
+ const batchPromise = this._processBatch(batch, {
617
+ apiUrl: batchKey === "default" ? undefined : batchKey.split("|")[0],
618
+ apiKey: batchKey === "default" ? undefined : batchKey.split("|")[1],
619
+ });
620
+ batchPromises.push(batchPromise);
621
+ }
622
+ // Wait for all batches to complete, then call the overall done callback
623
+ const allBatchesPromise = Promise.all(batchPromises).finally(done);
624
+ promises.push(allBatchesPromise);
590
625
  }
591
626
  return Promise.all(promises);
592
627
  }
593
- async _processBatch(batch, done) {
628
+ async _processBatch(batch, options) {
594
629
  if (!batch.length) {
595
- done();
596
630
  return;
597
631
  }
598
632
  try {
@@ -610,19 +644,16 @@ export class Client {
610
644
  };
611
645
  const serverInfo = await this._ensureServerInfo();
612
646
  if (serverInfo?.batch_ingest_config?.use_multipart_endpoint) {
613
- await this.multipartIngestRuns(ingestParams);
647
+ await this.multipartIngestRuns(ingestParams, options);
614
648
  }
615
649
  else {
616
- await this.batchIngestRuns(ingestParams);
650
+ await this.batchIngestRuns(ingestParams, options);
617
651
  }
618
652
  }
619
653
  }
620
654
  catch (e) {
621
655
  console.error("Error exporting batch:", e);
622
656
  }
623
- finally {
624
- done();
625
- }
626
657
  }
627
658
  _sendBatchToOTELTranslator(batch) {
628
659
  if (this.langSmithToOTELTranslator !== undefined) {
@@ -736,11 +767,14 @@ export class Client {
736
767
  }
737
768
  return undefined;
738
769
  }
739
- async createRun(run) {
770
+ async createRun(run, options) {
740
771
  if (!this._filterForSampling([run]).length) {
741
772
  return;
742
773
  }
743
- const headers = { ...this.headers, "Content-Type": "application/json" };
774
+ const headers = {
775
+ ...this.headers,
776
+ "Content-Type": "application/json",
777
+ };
744
778
  const session_name = run.project_name;
745
779
  delete run.project_name;
746
780
  const runCreate = await this.prepareRunCreateOrUpdateInputs({
@@ -756,11 +790,16 @@ export class Client {
756
790
  action: "create",
757
791
  item: runCreate,
758
792
  otelContext,
793
+ apiKey: options?.apiKey,
794
+ apiUrl: options?.apiUrl,
759
795
  }).catch(console.error);
760
796
  return;
761
797
  }
762
798
  const mergedRunCreateParam = mergeRuntimeEnvIntoRunCreate(runCreate);
763
- const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/runs`, {
799
+ if (options?.apiKey !== undefined) {
800
+ headers["x-api-key"] = options.apiKey;
801
+ }
802
+ const response = await this.caller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs`, {
764
803
  method: "POST",
765
804
  headers,
766
805
  body: serializePayloadForTracing(mergedRunCreateParam, `Creating run with id: ${mergedRunCreateParam.id}`),
@@ -773,7 +812,7 @@ export class Client {
773
812
  * Batch ingest/upsert multiple runs in the Langsmith system.
774
813
  * @param runs
775
814
  */
776
- async batchIngestRuns({ runCreates, runUpdates, }) {
815
+ async batchIngestRuns({ runCreates, runUpdates, }, options) {
777
816
  if (runCreates === undefined && runUpdates === undefined) {
778
817
  return;
779
818
  }
@@ -828,16 +867,19 @@ export class Client {
828
867
  .map((item) => item.id)
829
868
  .concat(batchChunks.patch.map((item) => item.id))
830
869
  .join(",");
831
- await this._postBatchIngestRuns(serializePayloadForTracing(batchChunks, `Ingesting runs with ids: ${runIds}`));
870
+ await this._postBatchIngestRuns(serializePayloadForTracing(batchChunks, `Ingesting runs with ids: ${runIds}`), options);
832
871
  }
833
872
  }
834
- async _postBatchIngestRuns(body) {
873
+ async _postBatchIngestRuns(body, options) {
835
874
  const headers = {
836
875
  ...this.headers,
837
876
  "Content-Type": "application/json",
838
877
  Accept: "application/json",
839
878
  };
840
- const response = await this.batchIngestCaller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/runs/batch`, {
879
+ if (options?.apiKey !== undefined) {
880
+ headers["x-api-key"] = options.apiKey;
881
+ }
882
+ const response = await this.batchIngestCaller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/batch`, {
841
883
  method: "POST",
842
884
  headers,
843
885
  body: body,
@@ -850,7 +892,7 @@ export class Client {
850
892
  * Batch ingest/upsert multiple runs in the Langsmith system.
851
893
  * @param runs
852
894
  */
853
- async multipartIngestRuns({ runCreates, runUpdates, }) {
895
+ async multipartIngestRuns({ runCreates, runUpdates, }, options) {
854
896
  if (runCreates === undefined && runUpdates === undefined) {
855
897
  return;
856
898
  }
@@ -977,7 +1019,7 @@ export class Client {
977
1019
  accumulatedContext.push(`trace=${payload.trace_id},id=${payload.id}`);
978
1020
  }
979
1021
  }
980
- await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "));
1022
+ await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "), options);
981
1023
  }
982
1024
  async _createNodeFetchBody(parts, boundary) {
983
1025
  // Create multipart form data manually using Blobs
@@ -1042,24 +1084,53 @@ export class Client {
1042
1084
  });
1043
1085
  return stream;
1044
1086
  }
1045
- async _sendMultipartRequest(parts, context) {
1046
- try {
1047
- // Create multipart form data boundary
1048
- const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
1049
- const body = await (_globalFetchImplementationIsNodeFetch()
1050
- ? this._createNodeFetchBody(parts, boundary)
1051
- : this._createMultipartStream(parts, boundary));
1052
- const res = await this.batchIngestCaller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/runs/multipart`, {
1087
+ async _sendMultipartRequest(parts, context, options) {
1088
+ // Create multipart form data boundary
1089
+ const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
1090
+ const isNodeFetch = _globalFetchImplementationIsNodeFetch();
1091
+ const buildBuffered = () => this._createNodeFetchBody(parts, boundary);
1092
+ const buildStream = () => this._createMultipartStream(parts, boundary);
1093
+ const send = async (body) => {
1094
+ const headers = {
1095
+ ...this.headers,
1096
+ "Content-Type": `multipart/form-data; boundary=${boundary}`,
1097
+ };
1098
+ if (options?.apiKey !== undefined) {
1099
+ headers["x-api-key"] = options.apiKey;
1100
+ }
1101
+ return this.batchIngestCaller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/multipart`, {
1053
1102
  method: "POST",
1054
- headers: {
1055
- ...this.headers,
1056
- "Content-Type": `multipart/form-data; boundary=${boundary}`,
1057
- },
1103
+ headers,
1058
1104
  body,
1059
1105
  duplex: "half",
1060
1106
  signal: AbortSignal.timeout(this.timeout_ms),
1061
1107
  ...this.fetchOptions,
1062
1108
  });
1109
+ };
1110
+ try {
1111
+ let res;
1112
+ let streamedAttempt = false;
1113
+ // attempt stream only if not disabled and not using node-fetch
1114
+ if (!isNodeFetch && !this.multipartStreamingDisabled) {
1115
+ streamedAttempt = true;
1116
+ res = await send(await buildStream());
1117
+ }
1118
+ else {
1119
+ res = await send(await buildBuffered());
1120
+ }
1121
+ // if stream fails, fallback to buffered body
1122
+ if ((!this.multipartStreamingDisabled || streamedAttempt) &&
1123
+ res.status === 422 &&
1124
+ (options?.apiUrl ?? this.apiUrl) !== DEFAULT_API_URL) {
1125
+ console.warn(`Streaming multipart upload to ${options?.apiUrl ?? this.apiUrl}/runs/multipart failed. ` +
1126
+ `This usually means the host does not support chunked uploads. ` +
1127
+ `Retrying with a buffered upload for operation "${context}".`);
1128
+ // Disable streaming for future requests
1129
+ this.multipartStreamingDisabled = true;
1130
+ // retry with fully-buffered body
1131
+ res = await send(await buildBuffered());
1132
+ }
1133
+ // raise if still failing
1063
1134
  await raiseForStatus(res, "ingest multipart runs", true);
1064
1135
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1065
1136
  }
@@ -1067,7 +1138,7 @@ export class Client {
1067
1138
  console.warn(`${e.message.trim()}\n\nContext: ${context}`);
1068
1139
  }
1069
1140
  }
1070
- async updateRun(runId, run) {
1141
+ async updateRun(runId, run, options) {
1071
1142
  assertUuid(runId);
1072
1143
  if (run.inputs) {
1073
1144
  run.inputs = await this.processInputs(run.inputs);
@@ -1094,6 +1165,8 @@ export class Client {
1094
1165
  action: "update",
1095
1166
  item: data,
1096
1167
  otelContext,
1168
+ apiKey: options?.apiKey,
1169
+ apiUrl: options?.apiUrl,
1097
1170
  }).catch(console.error);
1098
1171
  return;
1099
1172
  }
@@ -1102,12 +1175,20 @@ export class Client {
1102
1175
  action: "update",
1103
1176
  item: data,
1104
1177
  otelContext,
1178
+ apiKey: options?.apiKey,
1179
+ apiUrl: options?.apiUrl,
1105
1180
  }).catch(console.error);
1106
1181
  }
1107
1182
  return;
1108
1183
  }
1109
- const headers = { ...this.headers, "Content-Type": "application/json" };
1110
- const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/runs/${runId}`, {
1184
+ const headers = {
1185
+ ...this.headers,
1186
+ "Content-Type": "application/json",
1187
+ };
1188
+ if (options?.apiKey !== undefined) {
1189
+ headers["x-api-key"] = options.apiKey;
1190
+ }
1191
+ const response = await this.caller.call(_getFetchImplementation(this.debug), `${options?.apiUrl ?? this.apiUrl}/runs/${runId}`, {
1111
1192
  method: "PATCH",
1112
1193
  headers,
1113
1194
  body: serializePayloadForTracing(run, `Serializing payload to update run with id: ${runId}`),
@@ -3034,7 +3115,7 @@ export class Client {
3034
3115
  const settings = await this._getSettings();
3035
3116
  if (options?.isPublic && !settings.tenant_handle) {
3036
3117
  throw new Error(`Cannot create a public prompt without first\n
3037
- creating a LangChain Hub handle.
3118
+ creating a LangChain Hub handle.
3038
3119
  You can add a handle by creating a public prompt at:\n
3039
3120
  https://smith.langchain.com/prompts`);
3040
3121
  }
@@ -3152,7 +3233,7 @@ export class Client {
3152
3233
  }
3153
3234
  }
3154
3235
  const datasetIdToUse = datasetId ?? updates[0]?.dataset_id;
3155
- const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/v1/platform/datasets/${datasetIdToUse}/examples`, {
3236
+ const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetIdToUse}/examples`)}`, {
3156
3237
  method: "PATCH",
3157
3238
  headers: this.headers,
3158
3239
  body: formData,
@@ -3230,7 +3311,7 @@ export class Client {
3230
3311
  }
3231
3312
  }
3232
3313
  }
3233
- const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/v1/platform/datasets/${datasetId}/examples`, {
3314
+ const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}${this._getPlatformEndpointPath(`datasets/${datasetId}/examples`)}`, {
3234
3315
  method: "POST",
3235
3316
  headers: this.headers,
3236
3317
  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.41";
13
+ exports.__version__ = "0.3.43";
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.41";
6
+ export declare const __version__ = "0.3.43";
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.41";
6
+ export const __version__ = "0.3.43";
@@ -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 [projectName] of this.replicas) {
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 [projectName, updates] of this.replicas) {
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
+ }
@@ -27,7 +27,7 @@ export interface RunTreeConfig {
27
27
  trace_id?: string;
28
28
  dotted_order?: string;
29
29
  attachments?: Attachments;
30
- replicas?: [string, KVMap | undefined][];
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?: [string, KVMap | undefined][];
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 [projectName] of this.replicas) {
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 [projectName, updates] of this.replicas) {
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
+ }
@@ -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
+ }
@@ -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;
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.41",
3
+ "version": "0.3.43",
4
4
  "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
5
5
  "packageManager": "yarn@1.22.19",
6
6
  "files": [