langsmith 0.1.12 → 0.1.14

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/README.md CHANGED
@@ -292,6 +292,38 @@ export async function POST(req: Request) {
292
292
 
293
293
  See the [AI SDK docs](https://sdk.vercel.ai/docs) for more examples.
294
294
 
295
+ ## Arbitrary SDKs
296
+
297
+ You can use the generic `wrapSDK` method to add tracing for arbitrary SDKs.
298
+
299
+ Do note that this will trace ALL methods in the SDK, not just chat completion endpoints.
300
+ If the SDK you are wrapping has other methods, we recommend using it for only LLM calls.
301
+
302
+ Here's an example using the Anthropic SDK:
303
+
304
+ ```ts
305
+ import { wrapSDK } from "langsmith/wrappers";
306
+ import { Anthropic } from "@anthropic-ai/sdk";
307
+
308
+ const originalSDK = new Anthropic();
309
+ const sdkWithTracing = wrapSDK(originalSDK);
310
+
311
+ const response = await sdkWithTracing.messages.create({
312
+ messages: [
313
+ {
314
+ role: "user",
315
+ content: `What is 1 + 1? Respond only with "2" and nothing else.`,
316
+ },
317
+ ],
318
+ model: "claude-3-sonnet-20240229",
319
+ max_tokens: 1024,
320
+ });
321
+ ```
322
+
323
+ :::tip
324
+ [Click here](https://smith.langchain.com/public/0e7248af-bbed-47cf-be9f-5967fea1dec1/r) to see an example LangSmith trace of the above.
325
+ :::
326
+
295
327
  #### Alternatives: **Log traces using a RunTree.**
296
328
 
297
329
  A RunTree tracks your application. Each RunTree object is required to have a name and run_type. These and other important attributes are as follows:
package/dist/client.cjs CHANGED
@@ -265,6 +265,12 @@ class Client {
265
265
  writable: true,
266
266
  value: void 0
267
267
  });
268
+ Object.defineProperty(this, "fetchOptions", {
269
+ enumerable: true,
270
+ configurable: true,
271
+ writable: true,
272
+ value: void 0
273
+ });
268
274
  const defaultConfig = Client.getDefaultClientConfig();
269
275
  this.tracingSampleRate = getTracingSamplingRate();
270
276
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
@@ -281,6 +287,7 @@ class Client {
281
287
  this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
282
288
  this.pendingAutoBatchedRunLimit =
283
289
  config.pendingAutoBatchedRunLimit ?? this.pendingAutoBatchedRunLimit;
290
+ this.fetchOptions = config.fetchOptions || {};
284
291
  }
285
292
  static getDefaultClientConfig() {
286
293
  const apiKey = (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_API_KEY");
@@ -368,6 +375,7 @@ class Client {
368
375
  method: "GET",
369
376
  headers: this.headers,
370
377
  signal: AbortSignal.timeout(this.timeout_ms),
378
+ ...this.fetchOptions,
371
379
  });
372
380
  if (!response.ok) {
373
381
  throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
@@ -389,6 +397,7 @@ class Client {
389
397
  method: "GET",
390
398
  headers: this.headers,
391
399
  signal: AbortSignal.timeout(this.timeout_ms),
400
+ ...this.fetchOptions,
392
401
  });
393
402
  if (!response.ok) {
394
403
  throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
@@ -411,6 +420,7 @@ class Client {
411
420
  method: requestMethod,
412
421
  headers: { ...this.headers, "Content-Type": "application/json" },
413
422
  signal: AbortSignal.timeout(this.timeout_ms),
423
+ ...this.fetchOptions,
414
424
  body: JSON.stringify(bodyParams),
415
425
  });
416
426
  const responseBody = await response.json();
@@ -504,6 +514,7 @@ class Client {
504
514
  method: "GET",
505
515
  headers: { Accept: "application/json" },
506
516
  signal: AbortSignal.timeout(this.timeout_ms),
517
+ ...this.fetchOptions,
507
518
  });
508
519
  if (!response.ok) {
509
520
  // consume the response body to release the connection
@@ -551,6 +562,7 @@ class Client {
551
562
  headers,
552
563
  body: JSON.stringify(mergedRunCreateParams[0]),
553
564
  signal: AbortSignal.timeout(this.timeout_ms),
565
+ ...this.fetchOptions,
554
566
  });
555
567
  await raiseForStatus(response, "create run");
556
568
  }
@@ -650,6 +662,7 @@ class Client {
650
662
  headers,
651
663
  body: body,
652
664
  signal: AbortSignal.timeout(this.timeout_ms),
665
+ ...this.fetchOptions,
653
666
  });
654
667
  await raiseForStatus(response, "batch create run");
655
668
  }
@@ -686,6 +699,7 @@ class Client {
686
699
  headers,
687
700
  body: JSON.stringify(run),
688
701
  signal: AbortSignal.timeout(this.timeout_ms),
702
+ ...this.fetchOptions,
689
703
  });
690
704
  await raiseForStatus(response, "update run");
691
705
  }
@@ -880,6 +894,7 @@ class Client {
880
894
  headers: this.headers,
881
895
  body: JSON.stringify(data),
882
896
  signal: AbortSignal.timeout(this.timeout_ms),
897
+ ...this.fetchOptions,
883
898
  });
884
899
  const result = await response.json();
885
900
  if (result === null || !("share_token" in result)) {
@@ -893,6 +908,7 @@ class Client {
893
908
  method: "DELETE",
894
909
  headers: this.headers,
895
910
  signal: AbortSignal.timeout(this.timeout_ms),
911
+ ...this.fetchOptions,
896
912
  });
897
913
  await raiseForStatus(response, "unshare run");
898
914
  }
@@ -902,6 +918,7 @@ class Client {
902
918
  method: "GET",
903
919
  headers: this.headers,
904
920
  signal: AbortSignal.timeout(this.timeout_ms),
921
+ ...this.fetchOptions,
905
922
  });
906
923
  const result = await response.json();
907
924
  if (result === null || !("share_token" in result)) {
@@ -923,6 +940,7 @@ class Client {
923
940
  method: "GET",
924
941
  headers: this.headers,
925
942
  signal: AbortSignal.timeout(this.timeout_ms),
943
+ ...this.fetchOptions,
926
944
  });
927
945
  const runs = await response.json();
928
946
  return runs;
@@ -940,6 +958,7 @@ class Client {
940
958
  method: "GET",
941
959
  headers: this.headers,
942
960
  signal: AbortSignal.timeout(this.timeout_ms),
961
+ ...this.fetchOptions,
943
962
  });
944
963
  const shareSchema = await response.json();
945
964
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -962,6 +981,7 @@ class Client {
962
981
  headers: this.headers,
963
982
  body: JSON.stringify(data),
964
983
  signal: AbortSignal.timeout(this.timeout_ms),
984
+ ...this.fetchOptions,
965
985
  });
966
986
  const shareSchema = await response.json();
967
987
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -973,6 +993,7 @@ class Client {
973
993
  method: "DELETE",
974
994
  headers: this.headers,
975
995
  signal: AbortSignal.timeout(this.timeout_ms),
996
+ ...this.fetchOptions,
976
997
  });
977
998
  await raiseForStatus(response, "unshare dataset");
978
999
  }
@@ -982,6 +1003,7 @@ class Client {
982
1003
  method: "GET",
983
1004
  headers: this.headers,
984
1005
  signal: AbortSignal.timeout(this.timeout_ms),
1006
+ ...this.fetchOptions,
985
1007
  });
986
1008
  const dataset = await response.json();
987
1009
  return dataset;
@@ -1006,6 +1028,7 @@ class Client {
1006
1028
  headers: { ...this.headers, "Content-Type": "application/json" },
1007
1029
  body: JSON.stringify(body),
1008
1030
  signal: AbortSignal.timeout(this.timeout_ms),
1031
+ ...this.fetchOptions,
1009
1032
  });
1010
1033
  const result = await response.json();
1011
1034
  if (!response.ok) {
@@ -1030,6 +1053,7 @@ class Client {
1030
1053
  headers: { ...this.headers, "Content-Type": "application/json" },
1031
1054
  body: JSON.stringify(body),
1032
1055
  signal: AbortSignal.timeout(this.timeout_ms),
1056
+ ...this.fetchOptions,
1033
1057
  });
1034
1058
  const result = await response.json();
1035
1059
  if (!response.ok) {
@@ -1058,6 +1082,7 @@ class Client {
1058
1082
  method: "GET",
1059
1083
  headers: this.headers,
1060
1084
  signal: AbortSignal.timeout(this.timeout_ms),
1085
+ ...this.fetchOptions,
1061
1086
  });
1062
1087
  // consume the response body to release the connection
1063
1088
  // https://undici.nodejs.org/#/?id=garbage-collection
@@ -1168,6 +1193,7 @@ class Client {
1168
1193
  method: "DELETE",
1169
1194
  headers: this.headers,
1170
1195
  signal: AbortSignal.timeout(this.timeout_ms),
1196
+ ...this.fetchOptions,
1171
1197
  });
1172
1198
  await raiseForStatus(response, `delete session ${projectId_} (${projectName})`);
1173
1199
  }
@@ -1195,6 +1221,7 @@ class Client {
1195
1221
  headers: this.headers,
1196
1222
  body: formData,
1197
1223
  signal: AbortSignal.timeout(this.timeout_ms),
1224
+ ...this.fetchOptions,
1198
1225
  });
1199
1226
  if (!response.ok) {
1200
1227
  const result = await response.json();
@@ -1219,6 +1246,7 @@ class Client {
1219
1246
  headers: { ...this.headers, "Content-Type": "application/json" },
1220
1247
  body: JSON.stringify(body),
1221
1248
  signal: AbortSignal.timeout(this.timeout_ms),
1249
+ ...this.fetchOptions,
1222
1250
  });
1223
1251
  if (!response.ok) {
1224
1252
  const result = await response.json();
@@ -1260,6 +1288,27 @@ class Client {
1260
1288
  }
1261
1289
  return result;
1262
1290
  }
1291
+ async diffDatasetVersions({ datasetId, datasetName, fromVersion, toVersion, }) {
1292
+ let datasetId_ = datasetId;
1293
+ if (datasetId_ === undefined && datasetName === undefined) {
1294
+ throw new Error("Must provide either datasetName or datasetId");
1295
+ }
1296
+ else if (datasetId_ !== undefined && datasetName !== undefined) {
1297
+ throw new Error("Must provide either datasetName or datasetId, not both");
1298
+ }
1299
+ else if (datasetId_ === undefined) {
1300
+ const dataset = await this.readDataset({ datasetName });
1301
+ datasetId_ = dataset.id;
1302
+ }
1303
+ const urlParams = new URLSearchParams({
1304
+ from_version: typeof fromVersion === "string"
1305
+ ? fromVersion
1306
+ : fromVersion.toISOString(),
1307
+ to_version: typeof toVersion === "string" ? toVersion : toVersion.toISOString(),
1308
+ });
1309
+ const response = await this._get(`/datasets/${datasetId_}/versions/diff`, urlParams);
1310
+ return response;
1311
+ }
1263
1312
  async readDatasetOpenaiFinetuning({ datasetId, datasetName, }) {
1264
1313
  const path = "/datasets";
1265
1314
  if (datasetId !== undefined) {
@@ -1321,6 +1370,7 @@ class Client {
1321
1370
  method: "DELETE",
1322
1371
  headers: this.headers,
1323
1372
  signal: AbortSignal.timeout(this.timeout_ms),
1373
+ ...this.fetchOptions,
1324
1374
  });
1325
1375
  if (!response.ok) {
1326
1376
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1352,6 +1402,7 @@ class Client {
1352
1402
  headers: { ...this.headers, "Content-Type": "application/json" },
1353
1403
  body: JSON.stringify(data),
1354
1404
  signal: AbortSignal.timeout(this.timeout_ms),
1405
+ ...this.fetchOptions,
1355
1406
  });
1356
1407
  if (!response.ok) {
1357
1408
  throw new Error(`Failed to create example: ${response.status} ${response.statusText}`);
@@ -1386,6 +1437,7 @@ class Client {
1386
1437
  headers: { ...this.headers, "Content-Type": "application/json" },
1387
1438
  body: JSON.stringify(formattedExamples),
1388
1439
  signal: AbortSignal.timeout(this.timeout_ms),
1440
+ ...this.fetchOptions,
1389
1441
  });
1390
1442
  if (!response.ok) {
1391
1443
  throw new Error(`Failed to create examples: ${response.status} ${response.statusText}`);
@@ -1413,7 +1465,7 @@ class Client {
1413
1465
  const path = `/examples/${exampleId}`;
1414
1466
  return await this._get(path);
1415
1467
  }
1416
- async *listExamples({ datasetId, datasetName, exampleIds, } = {}) {
1468
+ async *listExamples({ datasetId, datasetName, exampleIds, asOf, inlineS3Urls, } = {}) {
1417
1469
  let datasetId_;
1418
1470
  if (datasetId !== undefined && datasetName !== undefined) {
1419
1471
  throw new Error("Must provide either datasetName or datasetId, not both");
@@ -1429,6 +1481,16 @@ class Client {
1429
1481
  throw new Error("Must provide a datasetName or datasetId");
1430
1482
  }
1431
1483
  const params = new URLSearchParams({ dataset: datasetId_ });
1484
+ const dataset_version = asOf
1485
+ ? typeof asOf === "string"
1486
+ ? asOf
1487
+ : asOf?.toISOString()
1488
+ : undefined;
1489
+ if (dataset_version) {
1490
+ params.append("as_of", dataset_version);
1491
+ }
1492
+ const inlineS3Urls_ = inlineS3Urls ?? true;
1493
+ params.append("inline_s3_urls", inlineS3Urls_.toString());
1432
1494
  if (exampleIds !== undefined) {
1433
1495
  for (const id_ of exampleIds) {
1434
1496
  params.append("id", id_);
@@ -1445,6 +1507,7 @@ class Client {
1445
1507
  method: "DELETE",
1446
1508
  headers: this.headers,
1447
1509
  signal: AbortSignal.timeout(this.timeout_ms),
1510
+ ...this.fetchOptions,
1448
1511
  });
1449
1512
  if (!response.ok) {
1450
1513
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1458,6 +1521,7 @@ class Client {
1458
1521
  headers: { ...this.headers, "Content-Type": "application/json" },
1459
1522
  body: JSON.stringify(update),
1460
1523
  signal: AbortSignal.timeout(this.timeout_ms),
1524
+ ...this.fetchOptions,
1461
1525
  });
1462
1526
  if (!response.ok) {
1463
1527
  throw new Error(`Failed to update example ${exampleId}: ${response.status} ${response.statusText}`);
@@ -1527,6 +1591,7 @@ class Client {
1527
1591
  headers: { ...this.headers, "Content-Type": "application/json" },
1528
1592
  body: JSON.stringify(feedback),
1529
1593
  signal: AbortSignal.timeout(this.timeout_ms),
1594
+ ...this.fetchOptions,
1530
1595
  });
1531
1596
  await raiseForStatus(response, "create feedback");
1532
1597
  return feedback;
@@ -1551,6 +1616,7 @@ class Client {
1551
1616
  headers: { ...this.headers, "Content-Type": "application/json" },
1552
1617
  body: JSON.stringify(feedbackUpdate),
1553
1618
  signal: AbortSignal.timeout(this.timeout_ms),
1619
+ ...this.fetchOptions,
1554
1620
  });
1555
1621
  await raiseForStatus(response, "update feedback");
1556
1622
  }
@@ -1567,6 +1633,7 @@ class Client {
1567
1633
  method: "DELETE",
1568
1634
  headers: this.headers,
1569
1635
  signal: AbortSignal.timeout(this.timeout_ms),
1636
+ ...this.fetchOptions,
1570
1637
  });
1571
1638
  if (!response.ok) {
1572
1639
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1631,6 +1698,7 @@ class Client {
1631
1698
  headers: { ...this.headers, "Content-Type": "application/json" },
1632
1699
  body: JSON.stringify(body),
1633
1700
  signal: AbortSignal.timeout(this.timeout_ms),
1701
+ ...this.fetchOptions,
1634
1702
  });
1635
1703
  const result = await response.json();
1636
1704
  return result;
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AsyncCallerParams } from "./utils/async_caller.js";
2
- import { DataType, Dataset, DatasetShareSchema, Example, ExampleUpdate, Feedback, FeedbackConfig, FeedbackIngestToken, KVMap, LangChainBaseMessage, Run, RunCreate, RunUpdate, ScoreType, TimeDelta, TracerSession, TracerSessionResult, ValueType } from "./schemas.js";
2
+ import { DataType, Dataset, DatasetDiffInfo, DatasetShareSchema, Example, ExampleUpdate, Feedback, FeedbackConfig, FeedbackIngestToken, KVMap, LangChainBaseMessage, Run, RunCreate, RunUpdate, ScoreType, TimeDelta, TracerSession, TracerSessionResult, ValueType } from "./schemas.js";
3
3
  import { RunEvaluator } from "./evaluation/evaluator.js";
4
4
  interface ClientConfig {
5
5
  apiUrl?: string;
@@ -11,6 +11,7 @@ interface ClientConfig {
11
11
  hideOutputs?: boolean;
12
12
  autoBatchTracing?: boolean;
13
13
  pendingAutoBatchedRunLimit?: number;
14
+ fetchOptions?: RequestInit;
14
15
  }
15
16
  /**
16
17
  * Represents the parameters for listing runs (spans) from the Langsmith server.
@@ -162,6 +163,7 @@ export declare class Client {
162
163
  private autoBatchInitialDelayMs;
163
164
  private autoBatchAggregationDelayMs;
164
165
  private serverInfo;
166
+ private fetchOptions;
165
167
  constructor(config?: ClientConfig);
166
168
  static getDefaultClientConfig(): {
167
169
  apiUrl: string;
@@ -344,6 +346,12 @@ export declare class Client {
344
346
  datasetId?: string;
345
347
  datasetName?: string;
346
348
  }): Promise<Dataset>;
349
+ diffDatasetVersions({ datasetId, datasetName, fromVersion, toVersion, }: {
350
+ datasetId?: string;
351
+ datasetName?: string;
352
+ fromVersion: string | Date;
353
+ toVersion: string | Date;
354
+ }): Promise<DatasetDiffInfo>;
347
355
  readDatasetOpenaiFinetuning({ datasetId, datasetName, }: {
348
356
  datasetId?: string;
349
357
  datasetName?: string;
@@ -371,10 +379,12 @@ export declare class Client {
371
379
  createLLMExample(input: string, generation: string | undefined, options: CreateExampleOptions): Promise<Example>;
372
380
  createChatExample(input: KVMap[] | LangChainBaseMessage[], generations: KVMap | LangChainBaseMessage | undefined, options: CreateExampleOptions): Promise<Example>;
373
381
  readExample(exampleId: string): Promise<Example>;
374
- listExamples({ datasetId, datasetName, exampleIds, }?: {
382
+ listExamples({ datasetId, datasetName, exampleIds, asOf, inlineS3Urls, }?: {
375
383
  datasetId?: string;
376
384
  datasetName?: string;
377
385
  exampleIds?: string[];
386
+ asOf?: string | Date;
387
+ inlineS3Urls?: boolean;
378
388
  }): AsyncIterable<Example>;
379
389
  deleteExample(exampleId: string): Promise<void>;
380
390
  updateExample(exampleId: string, update: ExampleUpdate): Promise<object>;
package/dist/client.js CHANGED
@@ -238,6 +238,12 @@ export class Client {
238
238
  writable: true,
239
239
  value: void 0
240
240
  });
241
+ Object.defineProperty(this, "fetchOptions", {
242
+ enumerable: true,
243
+ configurable: true,
244
+ writable: true,
245
+ value: void 0
246
+ });
241
247
  const defaultConfig = Client.getDefaultClientConfig();
242
248
  this.tracingSampleRate = getTracingSamplingRate();
243
249
  this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
@@ -254,6 +260,7 @@ export class Client {
254
260
  this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
255
261
  this.pendingAutoBatchedRunLimit =
256
262
  config.pendingAutoBatchedRunLimit ?? this.pendingAutoBatchedRunLimit;
263
+ this.fetchOptions = config.fetchOptions || {};
257
264
  }
258
265
  static getDefaultClientConfig() {
259
266
  const apiKey = getEnvironmentVariable("LANGCHAIN_API_KEY");
@@ -341,6 +348,7 @@ export class Client {
341
348
  method: "GET",
342
349
  headers: this.headers,
343
350
  signal: AbortSignal.timeout(this.timeout_ms),
351
+ ...this.fetchOptions,
344
352
  });
345
353
  if (!response.ok) {
346
354
  throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
@@ -362,6 +370,7 @@ export class Client {
362
370
  method: "GET",
363
371
  headers: this.headers,
364
372
  signal: AbortSignal.timeout(this.timeout_ms),
373
+ ...this.fetchOptions,
365
374
  });
366
375
  if (!response.ok) {
367
376
  throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
@@ -384,6 +393,7 @@ export class Client {
384
393
  method: requestMethod,
385
394
  headers: { ...this.headers, "Content-Type": "application/json" },
386
395
  signal: AbortSignal.timeout(this.timeout_ms),
396
+ ...this.fetchOptions,
387
397
  body: JSON.stringify(bodyParams),
388
398
  });
389
399
  const responseBody = await response.json();
@@ -477,6 +487,7 @@ export class Client {
477
487
  method: "GET",
478
488
  headers: { Accept: "application/json" },
479
489
  signal: AbortSignal.timeout(this.timeout_ms),
490
+ ...this.fetchOptions,
480
491
  });
481
492
  if (!response.ok) {
482
493
  // consume the response body to release the connection
@@ -524,6 +535,7 @@ export class Client {
524
535
  headers,
525
536
  body: JSON.stringify(mergedRunCreateParams[0]),
526
537
  signal: AbortSignal.timeout(this.timeout_ms),
538
+ ...this.fetchOptions,
527
539
  });
528
540
  await raiseForStatus(response, "create run");
529
541
  }
@@ -623,6 +635,7 @@ export class Client {
623
635
  headers,
624
636
  body: body,
625
637
  signal: AbortSignal.timeout(this.timeout_ms),
638
+ ...this.fetchOptions,
626
639
  });
627
640
  await raiseForStatus(response, "batch create run");
628
641
  }
@@ -659,6 +672,7 @@ export class Client {
659
672
  headers,
660
673
  body: JSON.stringify(run),
661
674
  signal: AbortSignal.timeout(this.timeout_ms),
675
+ ...this.fetchOptions,
662
676
  });
663
677
  await raiseForStatus(response, "update run");
664
678
  }
@@ -853,6 +867,7 @@ export class Client {
853
867
  headers: this.headers,
854
868
  body: JSON.stringify(data),
855
869
  signal: AbortSignal.timeout(this.timeout_ms),
870
+ ...this.fetchOptions,
856
871
  });
857
872
  const result = await response.json();
858
873
  if (result === null || !("share_token" in result)) {
@@ -866,6 +881,7 @@ export class Client {
866
881
  method: "DELETE",
867
882
  headers: this.headers,
868
883
  signal: AbortSignal.timeout(this.timeout_ms),
884
+ ...this.fetchOptions,
869
885
  });
870
886
  await raiseForStatus(response, "unshare run");
871
887
  }
@@ -875,6 +891,7 @@ export class Client {
875
891
  method: "GET",
876
892
  headers: this.headers,
877
893
  signal: AbortSignal.timeout(this.timeout_ms),
894
+ ...this.fetchOptions,
878
895
  });
879
896
  const result = await response.json();
880
897
  if (result === null || !("share_token" in result)) {
@@ -896,6 +913,7 @@ export class Client {
896
913
  method: "GET",
897
914
  headers: this.headers,
898
915
  signal: AbortSignal.timeout(this.timeout_ms),
916
+ ...this.fetchOptions,
899
917
  });
900
918
  const runs = await response.json();
901
919
  return runs;
@@ -913,6 +931,7 @@ export class Client {
913
931
  method: "GET",
914
932
  headers: this.headers,
915
933
  signal: AbortSignal.timeout(this.timeout_ms),
934
+ ...this.fetchOptions,
916
935
  });
917
936
  const shareSchema = await response.json();
918
937
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -935,6 +954,7 @@ export class Client {
935
954
  headers: this.headers,
936
955
  body: JSON.stringify(data),
937
956
  signal: AbortSignal.timeout(this.timeout_ms),
957
+ ...this.fetchOptions,
938
958
  });
939
959
  const shareSchema = await response.json();
940
960
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -946,6 +966,7 @@ export class Client {
946
966
  method: "DELETE",
947
967
  headers: this.headers,
948
968
  signal: AbortSignal.timeout(this.timeout_ms),
969
+ ...this.fetchOptions,
949
970
  });
950
971
  await raiseForStatus(response, "unshare dataset");
951
972
  }
@@ -955,6 +976,7 @@ export class Client {
955
976
  method: "GET",
956
977
  headers: this.headers,
957
978
  signal: AbortSignal.timeout(this.timeout_ms),
979
+ ...this.fetchOptions,
958
980
  });
959
981
  const dataset = await response.json();
960
982
  return dataset;
@@ -979,6 +1001,7 @@ export class Client {
979
1001
  headers: { ...this.headers, "Content-Type": "application/json" },
980
1002
  body: JSON.stringify(body),
981
1003
  signal: AbortSignal.timeout(this.timeout_ms),
1004
+ ...this.fetchOptions,
982
1005
  });
983
1006
  const result = await response.json();
984
1007
  if (!response.ok) {
@@ -1003,6 +1026,7 @@ export class Client {
1003
1026
  headers: { ...this.headers, "Content-Type": "application/json" },
1004
1027
  body: JSON.stringify(body),
1005
1028
  signal: AbortSignal.timeout(this.timeout_ms),
1029
+ ...this.fetchOptions,
1006
1030
  });
1007
1031
  const result = await response.json();
1008
1032
  if (!response.ok) {
@@ -1031,6 +1055,7 @@ export class Client {
1031
1055
  method: "GET",
1032
1056
  headers: this.headers,
1033
1057
  signal: AbortSignal.timeout(this.timeout_ms),
1058
+ ...this.fetchOptions,
1034
1059
  });
1035
1060
  // consume the response body to release the connection
1036
1061
  // https://undici.nodejs.org/#/?id=garbage-collection
@@ -1141,6 +1166,7 @@ export class Client {
1141
1166
  method: "DELETE",
1142
1167
  headers: this.headers,
1143
1168
  signal: AbortSignal.timeout(this.timeout_ms),
1169
+ ...this.fetchOptions,
1144
1170
  });
1145
1171
  await raiseForStatus(response, `delete session ${projectId_} (${projectName})`);
1146
1172
  }
@@ -1168,6 +1194,7 @@ export class Client {
1168
1194
  headers: this.headers,
1169
1195
  body: formData,
1170
1196
  signal: AbortSignal.timeout(this.timeout_ms),
1197
+ ...this.fetchOptions,
1171
1198
  });
1172
1199
  if (!response.ok) {
1173
1200
  const result = await response.json();
@@ -1192,6 +1219,7 @@ export class Client {
1192
1219
  headers: { ...this.headers, "Content-Type": "application/json" },
1193
1220
  body: JSON.stringify(body),
1194
1221
  signal: AbortSignal.timeout(this.timeout_ms),
1222
+ ...this.fetchOptions,
1195
1223
  });
1196
1224
  if (!response.ok) {
1197
1225
  const result = await response.json();
@@ -1233,6 +1261,27 @@ export class Client {
1233
1261
  }
1234
1262
  return result;
1235
1263
  }
1264
+ async diffDatasetVersions({ datasetId, datasetName, fromVersion, toVersion, }) {
1265
+ let datasetId_ = datasetId;
1266
+ if (datasetId_ === undefined && datasetName === undefined) {
1267
+ throw new Error("Must provide either datasetName or datasetId");
1268
+ }
1269
+ else if (datasetId_ !== undefined && datasetName !== undefined) {
1270
+ throw new Error("Must provide either datasetName or datasetId, not both");
1271
+ }
1272
+ else if (datasetId_ === undefined) {
1273
+ const dataset = await this.readDataset({ datasetName });
1274
+ datasetId_ = dataset.id;
1275
+ }
1276
+ const urlParams = new URLSearchParams({
1277
+ from_version: typeof fromVersion === "string"
1278
+ ? fromVersion
1279
+ : fromVersion.toISOString(),
1280
+ to_version: typeof toVersion === "string" ? toVersion : toVersion.toISOString(),
1281
+ });
1282
+ const response = await this._get(`/datasets/${datasetId_}/versions/diff`, urlParams);
1283
+ return response;
1284
+ }
1236
1285
  async readDatasetOpenaiFinetuning({ datasetId, datasetName, }) {
1237
1286
  const path = "/datasets";
1238
1287
  if (datasetId !== undefined) {
@@ -1294,6 +1343,7 @@ export class Client {
1294
1343
  method: "DELETE",
1295
1344
  headers: this.headers,
1296
1345
  signal: AbortSignal.timeout(this.timeout_ms),
1346
+ ...this.fetchOptions,
1297
1347
  });
1298
1348
  if (!response.ok) {
1299
1349
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1325,6 +1375,7 @@ export class Client {
1325
1375
  headers: { ...this.headers, "Content-Type": "application/json" },
1326
1376
  body: JSON.stringify(data),
1327
1377
  signal: AbortSignal.timeout(this.timeout_ms),
1378
+ ...this.fetchOptions,
1328
1379
  });
1329
1380
  if (!response.ok) {
1330
1381
  throw new Error(`Failed to create example: ${response.status} ${response.statusText}`);
@@ -1359,6 +1410,7 @@ export class Client {
1359
1410
  headers: { ...this.headers, "Content-Type": "application/json" },
1360
1411
  body: JSON.stringify(formattedExamples),
1361
1412
  signal: AbortSignal.timeout(this.timeout_ms),
1413
+ ...this.fetchOptions,
1362
1414
  });
1363
1415
  if (!response.ok) {
1364
1416
  throw new Error(`Failed to create examples: ${response.status} ${response.statusText}`);
@@ -1386,7 +1438,7 @@ export class Client {
1386
1438
  const path = `/examples/${exampleId}`;
1387
1439
  return await this._get(path);
1388
1440
  }
1389
- async *listExamples({ datasetId, datasetName, exampleIds, } = {}) {
1441
+ async *listExamples({ datasetId, datasetName, exampleIds, asOf, inlineS3Urls, } = {}) {
1390
1442
  let datasetId_;
1391
1443
  if (datasetId !== undefined && datasetName !== undefined) {
1392
1444
  throw new Error("Must provide either datasetName or datasetId, not both");
@@ -1402,6 +1454,16 @@ export class Client {
1402
1454
  throw new Error("Must provide a datasetName or datasetId");
1403
1455
  }
1404
1456
  const params = new URLSearchParams({ dataset: datasetId_ });
1457
+ const dataset_version = asOf
1458
+ ? typeof asOf === "string"
1459
+ ? asOf
1460
+ : asOf?.toISOString()
1461
+ : undefined;
1462
+ if (dataset_version) {
1463
+ params.append("as_of", dataset_version);
1464
+ }
1465
+ const inlineS3Urls_ = inlineS3Urls ?? true;
1466
+ params.append("inline_s3_urls", inlineS3Urls_.toString());
1405
1467
  if (exampleIds !== undefined) {
1406
1468
  for (const id_ of exampleIds) {
1407
1469
  params.append("id", id_);
@@ -1418,6 +1480,7 @@ export class Client {
1418
1480
  method: "DELETE",
1419
1481
  headers: this.headers,
1420
1482
  signal: AbortSignal.timeout(this.timeout_ms),
1483
+ ...this.fetchOptions,
1421
1484
  });
1422
1485
  if (!response.ok) {
1423
1486
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1431,6 +1494,7 @@ export class Client {
1431
1494
  headers: { ...this.headers, "Content-Type": "application/json" },
1432
1495
  body: JSON.stringify(update),
1433
1496
  signal: AbortSignal.timeout(this.timeout_ms),
1497
+ ...this.fetchOptions,
1434
1498
  });
1435
1499
  if (!response.ok) {
1436
1500
  throw new Error(`Failed to update example ${exampleId}: ${response.status} ${response.statusText}`);
@@ -1500,6 +1564,7 @@ export class Client {
1500
1564
  headers: { ...this.headers, "Content-Type": "application/json" },
1501
1565
  body: JSON.stringify(feedback),
1502
1566
  signal: AbortSignal.timeout(this.timeout_ms),
1567
+ ...this.fetchOptions,
1503
1568
  });
1504
1569
  await raiseForStatus(response, "create feedback");
1505
1570
  return feedback;
@@ -1524,6 +1589,7 @@ export class Client {
1524
1589
  headers: { ...this.headers, "Content-Type": "application/json" },
1525
1590
  body: JSON.stringify(feedbackUpdate),
1526
1591
  signal: AbortSignal.timeout(this.timeout_ms),
1592
+ ...this.fetchOptions,
1527
1593
  });
1528
1594
  await raiseForStatus(response, "update feedback");
1529
1595
  }
@@ -1540,6 +1606,7 @@ export class Client {
1540
1606
  method: "DELETE",
1541
1607
  headers: this.headers,
1542
1608
  signal: AbortSignal.timeout(this.timeout_ms),
1609
+ ...this.fetchOptions,
1543
1610
  });
1544
1611
  if (!response.ok) {
1545
1612
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1604,6 +1671,7 @@ export class Client {
1604
1671
  headers: { ...this.headers, "Content-Type": "application/json" },
1605
1672
  body: JSON.stringify(body),
1606
1673
  signal: AbortSignal.timeout(this.timeout_ms),
1674
+ ...this.fetchOptions,
1607
1675
  });
1608
1676
  const result = await response.json();
1609
1677
  return result;
package/dist/index.cjs CHANGED
@@ -6,4 +6,4 @@ Object.defineProperty(exports, "Client", { enumerable: true, get: function () {
6
6
  var run_trees_js_1 = require("./run_trees.cjs");
7
7
  Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () { return run_trees_js_1.RunTree; } });
8
8
  // Update using yarn bump-version
9
- exports.__version__ = "0.1.12";
9
+ exports.__version__ = "0.1.14";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Client } from "./client.js";
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
- export declare const __version__ = "0.1.12";
4
+ export declare const __version__ = "0.1.14";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Client } from "./client.js";
2
2
  export { RunTree } from "./run_trees.js";
3
3
  // Update using yarn bump-version
4
- export const __version__ = "0.1.12";
4
+ export const __version__ = "0.1.14";
package/dist/schemas.d.ts CHANGED
@@ -247,3 +247,8 @@ export interface FeedbackConfig {
247
247
  */
248
248
  categories?: FeedbackCategory[] | null;
249
249
  }
250
+ export interface DatasetDiffInfo {
251
+ examples_modified: string[];
252
+ examples_added: string[];
253
+ examples_removed: string[];
254
+ }
package/dist/wrappers.cjs CHANGED
@@ -1,12 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapOpenAI = void 0;
3
+ exports.wrapSDK = exports.wrapOpenAI = void 0;
4
4
  const traceable_js_1 = require("./traceable.cjs");
5
+ /**
6
+ * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
7
+ * tracing. Method signatures are unchanged.
8
+ * @param openai An OpenAI client instance.
9
+ * @param options LangSmith options.
10
+ * @returns
11
+ */
5
12
  const wrapOpenAI = (openai, options) => {
6
- // @ts-expect-error Promise<APIPromise<...>> != APIPromise<...>
7
13
  openai.chat.completions.create = (0, traceable_js_1.traceable)(openai.chat.completions.create.bind(openai.chat.completions), Object.assign({ name: "ChatOpenAI", run_type: "llm" }, options?.client));
8
- // @ts-expect-error Promise<APIPromise<...>> != APIPromise<...>
9
14
  openai.completions.create = (0, traceable_js_1.traceable)(openai.completions.create.bind(openai.completions), Object.assign({ name: "OpenAI", run_type: "llm" }, options?.client));
10
15
  return openai;
11
16
  };
12
17
  exports.wrapOpenAI = wrapOpenAI;
18
+ const _wrapClient = (sdk, runName, options) => {
19
+ return new Proxy(sdk, {
20
+ get(target, propKey, receiver) {
21
+ const originalValue = target[propKey];
22
+ if (typeof originalValue === "function") {
23
+ return (0, traceable_js_1.traceable)(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
24
+ }
25
+ else if (originalValue != null &&
26
+ !Array.isArray(originalValue) &&
27
+ // eslint-disable-next-line no-instanceof/no-instanceof
28
+ !(originalValue instanceof Date) &&
29
+ typeof originalValue === "object") {
30
+ return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
31
+ }
32
+ else {
33
+ return Reflect.get(target, propKey, receiver);
34
+ }
35
+ },
36
+ });
37
+ };
38
+ /**
39
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
40
+ * Method signatures are unchanged.
41
+ *
42
+ * Note that this will wrap and trace ALL SDK methods, not just
43
+ * LLM completion methods. If the passed SDK contains other methods,
44
+ * we recommend using the wrapped instance for LLM calls only.
45
+ * @param sdk An arbitrary SDK instance.
46
+ * @param options LangSmith options.
47
+ * @returns
48
+ */
49
+ const wrapSDK = (sdk, options) => {
50
+ return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
51
+ client: options?.client,
52
+ });
53
+ };
54
+ exports.wrapSDK = wrapSDK;
@@ -1,5 +1,37 @@
1
- import type { OpenAI } from "openai";
2
1
  import type { Client } from "./index.js";
3
- export declare const wrapOpenAI: (openai: OpenAI, options?: {
2
+ type OpenAIType = {
3
+ chat: {
4
+ completions: {
5
+ create: (...args: any[]) => any;
6
+ };
7
+ };
8
+ completions: {
9
+ create: (...args: any[]) => any;
10
+ };
11
+ };
12
+ /**
13
+ * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
14
+ * tracing. Method signatures are unchanged.
15
+ * @param openai An OpenAI client instance.
16
+ * @param options LangSmith options.
17
+ * @returns
18
+ */
19
+ export declare const wrapOpenAI: <T extends OpenAIType>(openai: T, options?: {
4
20
  client?: Client;
5
- }) => OpenAI;
21
+ }) => T;
22
+ /**
23
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
24
+ * Method signatures are unchanged.
25
+ *
26
+ * Note that this will wrap and trace ALL SDK methods, not just
27
+ * LLM completion methods. If the passed SDK contains other methods,
28
+ * we recommend using the wrapped instance for LLM calls only.
29
+ * @param sdk An arbitrary SDK instance.
30
+ * @param options LangSmith options.
31
+ * @returns
32
+ */
33
+ export declare const wrapSDK: <T extends object>(sdk: T, options?: {
34
+ client?: Client;
35
+ runName?: string;
36
+ }) => T;
37
+ export {};
package/dist/wrappers.js CHANGED
@@ -1,8 +1,49 @@
1
1
  import { traceable } from "./traceable.js";
2
+ /**
3
+ * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
4
+ * tracing. Method signatures are unchanged.
5
+ * @param openai An OpenAI client instance.
6
+ * @param options LangSmith options.
7
+ * @returns
8
+ */
2
9
  export const wrapOpenAI = (openai, options) => {
3
- // @ts-expect-error Promise<APIPromise<...>> != APIPromise<...>
4
10
  openai.chat.completions.create = traceable(openai.chat.completions.create.bind(openai.chat.completions), Object.assign({ name: "ChatOpenAI", run_type: "llm" }, options?.client));
5
- // @ts-expect-error Promise<APIPromise<...>> != APIPromise<...>
6
11
  openai.completions.create = traceable(openai.completions.create.bind(openai.completions), Object.assign({ name: "OpenAI", run_type: "llm" }, options?.client));
7
12
  return openai;
8
13
  };
14
+ const _wrapClient = (sdk, runName, options) => {
15
+ return new Proxy(sdk, {
16
+ get(target, propKey, receiver) {
17
+ const originalValue = target[propKey];
18
+ if (typeof originalValue === "function") {
19
+ return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
20
+ }
21
+ else if (originalValue != null &&
22
+ !Array.isArray(originalValue) &&
23
+ // eslint-disable-next-line no-instanceof/no-instanceof
24
+ !(originalValue instanceof Date) &&
25
+ typeof originalValue === "object") {
26
+ return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
27
+ }
28
+ else {
29
+ return Reflect.get(target, propKey, receiver);
30
+ }
31
+ },
32
+ });
33
+ };
34
+ /**
35
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
36
+ * Method signatures are unchanged.
37
+ *
38
+ * Note that this will wrap and trace ALL SDK methods, not just
39
+ * LLM completion methods. If the passed SDK contains other methods,
40
+ * we recommend using the wrapped instance for LLM calls only.
41
+ * @param sdk An arbitrary SDK instance.
42
+ * @param options LangSmith options.
43
+ * @returns
44
+ */
45
+ export const wrapSDK = (sdk, options) => {
46
+ return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
47
+ client: options?.client,
48
+ });
49
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
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": [