langsmith 0.1.13 → 0.1.18

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/client.d.cts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/client.js'
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
  }
@@ -763,7 +777,7 @@ class Client {
763
777
  * @param traceId - The ID of the trace to filter by.
764
778
  * @param referenceExampleId - The ID of the reference example to filter by.
765
779
  * @param startTime - The start time to filter by.
766
- * @param executionOrder - The execution order to filter by.
780
+ * @param isRoot - Indicates whether to only return root runs.
767
781
  * @param runType - The run type to filter by.
768
782
  * @param error - Indicates whether to filter by error runs.
769
783
  * @param id - The ID of the run to filter by.
@@ -837,7 +851,7 @@ class Client {
837
851
  * });
838
852
  */
839
853
  async *listRuns(props) {
840
- const { projectId, projectName, parentRunId, traceId, referenceExampleId, startTime, executionOrder, runType, error, id, query, filter, traceFilter, treeFilter, limit, } = props;
854
+ const { projectId, projectName, parentRunId, traceId, referenceExampleId, startTime, executionOrder, isRoot, runType, error, id, query, filter, traceFilter, treeFilter, limit, select, } = props;
841
855
  let projectIds = [];
842
856
  if (projectId) {
843
857
  projectIds = Array.isArray(projectId) ? projectId : [projectId];
@@ -849,6 +863,36 @@ class Client {
849
863
  const projectIds_ = await Promise.all(projectNames.map((name) => this.readProject({ projectName: name }).then((project) => project.id)));
850
864
  projectIds.push(...projectIds_);
851
865
  }
866
+ const default_select = [
867
+ "app_path",
868
+ "child_run_ids",
869
+ "completion_cost",
870
+ "completion_tokens",
871
+ "dotted_order",
872
+ "end_time",
873
+ "error",
874
+ "events",
875
+ "extra",
876
+ "feedback_stats",
877
+ "first_token_time",
878
+ "id",
879
+ "inputs",
880
+ "name",
881
+ "outputs",
882
+ "parent_run_id",
883
+ "parent_run_ids",
884
+ "prompt_cost",
885
+ "prompt_tokens",
886
+ "reference_example_id",
887
+ "run_type",
888
+ "session_id",
889
+ "start_time",
890
+ "status",
891
+ "tags",
892
+ "total_cost",
893
+ "total_tokens",
894
+ "trace_id",
895
+ ];
852
896
  const body = {
853
897
  session: projectIds.length ? projectIds : null,
854
898
  run_type: runType,
@@ -864,6 +908,8 @@ class Client {
864
908
  id,
865
909
  limit,
866
910
  trace: traceId,
911
+ select: select ? select : default_select,
912
+ is_root: isRoot,
867
913
  };
868
914
  for await (const runs of this._getCursorPaginatedList("/runs/query", body)) {
869
915
  yield* runs;
@@ -880,6 +926,7 @@ class Client {
880
926
  headers: this.headers,
881
927
  body: JSON.stringify(data),
882
928
  signal: AbortSignal.timeout(this.timeout_ms),
929
+ ...this.fetchOptions,
883
930
  });
884
931
  const result = await response.json();
885
932
  if (result === null || !("share_token" in result)) {
@@ -893,6 +940,7 @@ class Client {
893
940
  method: "DELETE",
894
941
  headers: this.headers,
895
942
  signal: AbortSignal.timeout(this.timeout_ms),
943
+ ...this.fetchOptions,
896
944
  });
897
945
  await raiseForStatus(response, "unshare run");
898
946
  }
@@ -902,6 +950,7 @@ class Client {
902
950
  method: "GET",
903
951
  headers: this.headers,
904
952
  signal: AbortSignal.timeout(this.timeout_ms),
953
+ ...this.fetchOptions,
905
954
  });
906
955
  const result = await response.json();
907
956
  if (result === null || !("share_token" in result)) {
@@ -923,6 +972,7 @@ class Client {
923
972
  method: "GET",
924
973
  headers: this.headers,
925
974
  signal: AbortSignal.timeout(this.timeout_ms),
975
+ ...this.fetchOptions,
926
976
  });
927
977
  const runs = await response.json();
928
978
  return runs;
@@ -940,6 +990,7 @@ class Client {
940
990
  method: "GET",
941
991
  headers: this.headers,
942
992
  signal: AbortSignal.timeout(this.timeout_ms),
993
+ ...this.fetchOptions,
943
994
  });
944
995
  const shareSchema = await response.json();
945
996
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -962,6 +1013,7 @@ class Client {
962
1013
  headers: this.headers,
963
1014
  body: JSON.stringify(data),
964
1015
  signal: AbortSignal.timeout(this.timeout_ms),
1016
+ ...this.fetchOptions,
965
1017
  });
966
1018
  const shareSchema = await response.json();
967
1019
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -973,6 +1025,7 @@ class Client {
973
1025
  method: "DELETE",
974
1026
  headers: this.headers,
975
1027
  signal: AbortSignal.timeout(this.timeout_ms),
1028
+ ...this.fetchOptions,
976
1029
  });
977
1030
  await raiseForStatus(response, "unshare dataset");
978
1031
  }
@@ -982,6 +1035,7 @@ class Client {
982
1035
  method: "GET",
983
1036
  headers: this.headers,
984
1037
  signal: AbortSignal.timeout(this.timeout_ms),
1038
+ ...this.fetchOptions,
985
1039
  });
986
1040
  const dataset = await response.json();
987
1041
  return dataset;
@@ -1006,6 +1060,7 @@ class Client {
1006
1060
  headers: { ...this.headers, "Content-Type": "application/json" },
1007
1061
  body: JSON.stringify(body),
1008
1062
  signal: AbortSignal.timeout(this.timeout_ms),
1063
+ ...this.fetchOptions,
1009
1064
  });
1010
1065
  const result = await response.json();
1011
1066
  if (!response.ok) {
@@ -1030,6 +1085,7 @@ class Client {
1030
1085
  headers: { ...this.headers, "Content-Type": "application/json" },
1031
1086
  body: JSON.stringify(body),
1032
1087
  signal: AbortSignal.timeout(this.timeout_ms),
1088
+ ...this.fetchOptions,
1033
1089
  });
1034
1090
  const result = await response.json();
1035
1091
  if (!response.ok) {
@@ -1058,6 +1114,7 @@ class Client {
1058
1114
  method: "GET",
1059
1115
  headers: this.headers,
1060
1116
  signal: AbortSignal.timeout(this.timeout_ms),
1117
+ ...this.fetchOptions,
1061
1118
  });
1062
1119
  // consume the response body to release the connection
1063
1120
  // https://undici.nodejs.org/#/?id=garbage-collection
@@ -1168,6 +1225,7 @@ class Client {
1168
1225
  method: "DELETE",
1169
1226
  headers: this.headers,
1170
1227
  signal: AbortSignal.timeout(this.timeout_ms),
1228
+ ...this.fetchOptions,
1171
1229
  });
1172
1230
  await raiseForStatus(response, `delete session ${projectId_} (${projectName})`);
1173
1231
  }
@@ -1195,6 +1253,7 @@ class Client {
1195
1253
  headers: this.headers,
1196
1254
  body: formData,
1197
1255
  signal: AbortSignal.timeout(this.timeout_ms),
1256
+ ...this.fetchOptions,
1198
1257
  });
1199
1258
  if (!response.ok) {
1200
1259
  const result = await response.json();
@@ -1219,6 +1278,7 @@ class Client {
1219
1278
  headers: { ...this.headers, "Content-Type": "application/json" },
1220
1279
  body: JSON.stringify(body),
1221
1280
  signal: AbortSignal.timeout(this.timeout_ms),
1281
+ ...this.fetchOptions,
1222
1282
  });
1223
1283
  if (!response.ok) {
1224
1284
  const result = await response.json();
@@ -1342,13 +1402,14 @@ class Client {
1342
1402
  method: "DELETE",
1343
1403
  headers: this.headers,
1344
1404
  signal: AbortSignal.timeout(this.timeout_ms),
1405
+ ...this.fetchOptions,
1345
1406
  });
1346
1407
  if (!response.ok) {
1347
1408
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
1348
1409
  }
1349
1410
  await response.json();
1350
1411
  }
1351
- async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId }) {
1412
+ async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId, metadata, }) {
1352
1413
  let datasetId_ = datasetId;
1353
1414
  if (datasetId_ === undefined && datasetName === undefined) {
1354
1415
  throw new Error("Must provide either datasetName or datasetId");
@@ -1367,12 +1428,14 @@ class Client {
1367
1428
  outputs,
1368
1429
  created_at: createdAt_?.toISOString(),
1369
1430
  id: exampleId,
1431
+ metadata,
1370
1432
  };
1371
1433
  const response = await this.caller.call(fetch, `${this.apiUrl}/examples`, {
1372
1434
  method: "POST",
1373
1435
  headers: { ...this.headers, "Content-Type": "application/json" },
1374
1436
  body: JSON.stringify(data),
1375
1437
  signal: AbortSignal.timeout(this.timeout_ms),
1438
+ ...this.fetchOptions,
1376
1439
  });
1377
1440
  if (!response.ok) {
1378
1441
  throw new Error(`Failed to create example: ${response.status} ${response.statusText}`);
@@ -1381,7 +1444,7 @@ class Client {
1381
1444
  return result;
1382
1445
  }
1383
1446
  async createExamples(props) {
1384
- const { inputs, outputs, sourceRunIds, exampleIds, datasetId, datasetName, } = props;
1447
+ const { inputs, outputs, metadata, sourceRunIds, exampleIds, datasetId, datasetName, } = props;
1385
1448
  let datasetId_ = datasetId;
1386
1449
  if (datasetId_ === undefined && datasetName === undefined) {
1387
1450
  throw new Error("Must provide either datasetName or datasetId");
@@ -1398,6 +1461,7 @@ class Client {
1398
1461
  dataset_id: datasetId_,
1399
1462
  inputs: input,
1400
1463
  outputs: outputs ? outputs[idx] : undefined,
1464
+ metadata: metadata ? metadata[idx] : undefined,
1401
1465
  id: exampleIds ? exampleIds[idx] : undefined,
1402
1466
  source_run_id: sourceRunIds ? sourceRunIds[idx] : undefined,
1403
1467
  };
@@ -1407,6 +1471,7 @@ class Client {
1407
1471
  headers: { ...this.headers, "Content-Type": "application/json" },
1408
1472
  body: JSON.stringify(formattedExamples),
1409
1473
  signal: AbortSignal.timeout(this.timeout_ms),
1474
+ ...this.fetchOptions,
1410
1475
  });
1411
1476
  if (!response.ok) {
1412
1477
  throw new Error(`Failed to create examples: ${response.status} ${response.statusText}`);
@@ -1476,6 +1541,7 @@ class Client {
1476
1541
  method: "DELETE",
1477
1542
  headers: this.headers,
1478
1543
  signal: AbortSignal.timeout(this.timeout_ms),
1544
+ ...this.fetchOptions,
1479
1545
  });
1480
1546
  if (!response.ok) {
1481
1547
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1489,6 +1555,7 @@ class Client {
1489
1555
  headers: { ...this.headers, "Content-Type": "application/json" },
1490
1556
  body: JSON.stringify(update),
1491
1557
  signal: AbortSignal.timeout(this.timeout_ms),
1558
+ ...this.fetchOptions,
1492
1559
  });
1493
1560
  if (!response.ok) {
1494
1561
  throw new Error(`Failed to update example ${exampleId}: ${response.status} ${response.statusText}`);
@@ -1558,6 +1625,7 @@ class Client {
1558
1625
  headers: { ...this.headers, "Content-Type": "application/json" },
1559
1626
  body: JSON.stringify(feedback),
1560
1627
  signal: AbortSignal.timeout(this.timeout_ms),
1628
+ ...this.fetchOptions,
1561
1629
  });
1562
1630
  await raiseForStatus(response, "create feedback");
1563
1631
  return feedback;
@@ -1582,6 +1650,7 @@ class Client {
1582
1650
  headers: { ...this.headers, "Content-Type": "application/json" },
1583
1651
  body: JSON.stringify(feedbackUpdate),
1584
1652
  signal: AbortSignal.timeout(this.timeout_ms),
1653
+ ...this.fetchOptions,
1585
1654
  });
1586
1655
  await raiseForStatus(response, "update feedback");
1587
1656
  }
@@ -1598,6 +1667,7 @@ class Client {
1598
1667
  method: "DELETE",
1599
1668
  headers: this.headers,
1600
1669
  signal: AbortSignal.timeout(this.timeout_ms),
1670
+ ...this.fetchOptions,
1601
1671
  });
1602
1672
  if (!response.ok) {
1603
1673
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1662,6 +1732,7 @@ class Client {
1662
1732
  headers: { ...this.headers, "Content-Type": "application/json" },
1663
1733
  body: JSON.stringify(body),
1664
1734
  signal: AbortSignal.timeout(this.timeout_ms),
1735
+ ...this.fetchOptions,
1665
1736
  });
1666
1737
  const result = await response.json();
1667
1738
  return result;
package/dist/client.d.ts CHANGED
@@ -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.
@@ -28,6 +29,10 @@ interface ListRunsParams {
28
29
  * The ID of the trace to filter by.
29
30
  */
30
31
  traceId?: string;
32
+ /**
33
+ * isRoot - Whether to only include root runs.
34
+ * */
35
+ isRoot?: boolean;
31
36
  /**
32
37
  * The execution order to filter by.
33
38
  */
@@ -95,6 +100,11 @@ interface ListRunsParams {
95
100
  * conjunction with the regular `filter` parameter to let you filter runs by attributes of any run within a trace.
96
101
  */
97
102
  treeFilter?: string;
103
+ /**
104
+ * The values to include in the response.
105
+ *
106
+ */
107
+ select?: string[];
98
108
  }
99
109
  interface UploadCSVParams {
100
110
  csvFile: Blob;
@@ -134,6 +144,7 @@ export type CreateExampleOptions = {
134
144
  datasetName?: string;
135
145
  createdAt?: Date;
136
146
  exampleId?: string;
147
+ metadata?: KVMap;
137
148
  };
138
149
  export declare class Queue<T> {
139
150
  items: [T, () => void][];
@@ -162,6 +173,7 @@ export declare class Client {
162
173
  private autoBatchInitialDelayMs;
163
174
  private autoBatchAggregationDelayMs;
164
175
  private serverInfo;
176
+ private fetchOptions;
165
177
  constructor(config?: ClientConfig);
166
178
  static getDefaultClientConfig(): {
167
179
  apiUrl: string;
@@ -212,7 +224,7 @@ export declare class Client {
212
224
  * @param traceId - The ID of the trace to filter by.
213
225
  * @param referenceExampleId - The ID of the reference example to filter by.
214
226
  * @param startTime - The start time to filter by.
215
- * @param executionOrder - The execution order to filter by.
227
+ * @param isRoot - Indicates whether to only return root runs.
216
228
  * @param runType - The run type to filter by.
217
229
  * @param error - Indicates whether to filter by error runs.
218
230
  * @param id - The ID of the run to filter by.
@@ -365,10 +377,11 @@ export declare class Client {
365
377
  datasetId?: string;
366
378
  datasetName?: string;
367
379
  }): Promise<void>;
368
- createExample(inputs: KVMap, outputs: KVMap, { datasetId, datasetName, createdAt, exampleId }: CreateExampleOptions): Promise<Example>;
380
+ createExample(inputs: KVMap, outputs: KVMap, { datasetId, datasetName, createdAt, exampleId, metadata, }: CreateExampleOptions): Promise<Example>;
369
381
  createExamples(props: {
370
382
  inputs: Array<KVMap>;
371
383
  outputs?: Array<KVMap>;
384
+ metadata?: Array<KVMap>;
372
385
  sourceRunIds?: Array<string>;
373
386
  exampleIds?: Array<string>;
374
387
  datasetId?: string;
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
  }
@@ -736,7 +750,7 @@ export class Client {
736
750
  * @param traceId - The ID of the trace to filter by.
737
751
  * @param referenceExampleId - The ID of the reference example to filter by.
738
752
  * @param startTime - The start time to filter by.
739
- * @param executionOrder - The execution order to filter by.
753
+ * @param isRoot - Indicates whether to only return root runs.
740
754
  * @param runType - The run type to filter by.
741
755
  * @param error - Indicates whether to filter by error runs.
742
756
  * @param id - The ID of the run to filter by.
@@ -810,7 +824,7 @@ export class Client {
810
824
  * });
811
825
  */
812
826
  async *listRuns(props) {
813
- const { projectId, projectName, parentRunId, traceId, referenceExampleId, startTime, executionOrder, runType, error, id, query, filter, traceFilter, treeFilter, limit, } = props;
827
+ const { projectId, projectName, parentRunId, traceId, referenceExampleId, startTime, executionOrder, isRoot, runType, error, id, query, filter, traceFilter, treeFilter, limit, select, } = props;
814
828
  let projectIds = [];
815
829
  if (projectId) {
816
830
  projectIds = Array.isArray(projectId) ? projectId : [projectId];
@@ -822,6 +836,36 @@ export class Client {
822
836
  const projectIds_ = await Promise.all(projectNames.map((name) => this.readProject({ projectName: name }).then((project) => project.id)));
823
837
  projectIds.push(...projectIds_);
824
838
  }
839
+ const default_select = [
840
+ "app_path",
841
+ "child_run_ids",
842
+ "completion_cost",
843
+ "completion_tokens",
844
+ "dotted_order",
845
+ "end_time",
846
+ "error",
847
+ "events",
848
+ "extra",
849
+ "feedback_stats",
850
+ "first_token_time",
851
+ "id",
852
+ "inputs",
853
+ "name",
854
+ "outputs",
855
+ "parent_run_id",
856
+ "parent_run_ids",
857
+ "prompt_cost",
858
+ "prompt_tokens",
859
+ "reference_example_id",
860
+ "run_type",
861
+ "session_id",
862
+ "start_time",
863
+ "status",
864
+ "tags",
865
+ "total_cost",
866
+ "total_tokens",
867
+ "trace_id",
868
+ ];
825
869
  const body = {
826
870
  session: projectIds.length ? projectIds : null,
827
871
  run_type: runType,
@@ -837,6 +881,8 @@ export class Client {
837
881
  id,
838
882
  limit,
839
883
  trace: traceId,
884
+ select: select ? select : default_select,
885
+ is_root: isRoot,
840
886
  };
841
887
  for await (const runs of this._getCursorPaginatedList("/runs/query", body)) {
842
888
  yield* runs;
@@ -853,6 +899,7 @@ export class Client {
853
899
  headers: this.headers,
854
900
  body: JSON.stringify(data),
855
901
  signal: AbortSignal.timeout(this.timeout_ms),
902
+ ...this.fetchOptions,
856
903
  });
857
904
  const result = await response.json();
858
905
  if (result === null || !("share_token" in result)) {
@@ -866,6 +913,7 @@ export class Client {
866
913
  method: "DELETE",
867
914
  headers: this.headers,
868
915
  signal: AbortSignal.timeout(this.timeout_ms),
916
+ ...this.fetchOptions,
869
917
  });
870
918
  await raiseForStatus(response, "unshare run");
871
919
  }
@@ -875,6 +923,7 @@ export class Client {
875
923
  method: "GET",
876
924
  headers: this.headers,
877
925
  signal: AbortSignal.timeout(this.timeout_ms),
926
+ ...this.fetchOptions,
878
927
  });
879
928
  const result = await response.json();
880
929
  if (result === null || !("share_token" in result)) {
@@ -896,6 +945,7 @@ export class Client {
896
945
  method: "GET",
897
946
  headers: this.headers,
898
947
  signal: AbortSignal.timeout(this.timeout_ms),
948
+ ...this.fetchOptions,
899
949
  });
900
950
  const runs = await response.json();
901
951
  return runs;
@@ -913,6 +963,7 @@ export class Client {
913
963
  method: "GET",
914
964
  headers: this.headers,
915
965
  signal: AbortSignal.timeout(this.timeout_ms),
966
+ ...this.fetchOptions,
916
967
  });
917
968
  const shareSchema = await response.json();
918
969
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -935,6 +986,7 @@ export class Client {
935
986
  headers: this.headers,
936
987
  body: JSON.stringify(data),
937
988
  signal: AbortSignal.timeout(this.timeout_ms),
989
+ ...this.fetchOptions,
938
990
  });
939
991
  const shareSchema = await response.json();
940
992
  shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
@@ -946,6 +998,7 @@ export class Client {
946
998
  method: "DELETE",
947
999
  headers: this.headers,
948
1000
  signal: AbortSignal.timeout(this.timeout_ms),
1001
+ ...this.fetchOptions,
949
1002
  });
950
1003
  await raiseForStatus(response, "unshare dataset");
951
1004
  }
@@ -955,6 +1008,7 @@ export class Client {
955
1008
  method: "GET",
956
1009
  headers: this.headers,
957
1010
  signal: AbortSignal.timeout(this.timeout_ms),
1011
+ ...this.fetchOptions,
958
1012
  });
959
1013
  const dataset = await response.json();
960
1014
  return dataset;
@@ -979,6 +1033,7 @@ export class Client {
979
1033
  headers: { ...this.headers, "Content-Type": "application/json" },
980
1034
  body: JSON.stringify(body),
981
1035
  signal: AbortSignal.timeout(this.timeout_ms),
1036
+ ...this.fetchOptions,
982
1037
  });
983
1038
  const result = await response.json();
984
1039
  if (!response.ok) {
@@ -1003,6 +1058,7 @@ export class Client {
1003
1058
  headers: { ...this.headers, "Content-Type": "application/json" },
1004
1059
  body: JSON.stringify(body),
1005
1060
  signal: AbortSignal.timeout(this.timeout_ms),
1061
+ ...this.fetchOptions,
1006
1062
  });
1007
1063
  const result = await response.json();
1008
1064
  if (!response.ok) {
@@ -1031,6 +1087,7 @@ export class Client {
1031
1087
  method: "GET",
1032
1088
  headers: this.headers,
1033
1089
  signal: AbortSignal.timeout(this.timeout_ms),
1090
+ ...this.fetchOptions,
1034
1091
  });
1035
1092
  // consume the response body to release the connection
1036
1093
  // https://undici.nodejs.org/#/?id=garbage-collection
@@ -1141,6 +1198,7 @@ export class Client {
1141
1198
  method: "DELETE",
1142
1199
  headers: this.headers,
1143
1200
  signal: AbortSignal.timeout(this.timeout_ms),
1201
+ ...this.fetchOptions,
1144
1202
  });
1145
1203
  await raiseForStatus(response, `delete session ${projectId_} (${projectName})`);
1146
1204
  }
@@ -1168,6 +1226,7 @@ export class Client {
1168
1226
  headers: this.headers,
1169
1227
  body: formData,
1170
1228
  signal: AbortSignal.timeout(this.timeout_ms),
1229
+ ...this.fetchOptions,
1171
1230
  });
1172
1231
  if (!response.ok) {
1173
1232
  const result = await response.json();
@@ -1192,6 +1251,7 @@ export class Client {
1192
1251
  headers: { ...this.headers, "Content-Type": "application/json" },
1193
1252
  body: JSON.stringify(body),
1194
1253
  signal: AbortSignal.timeout(this.timeout_ms),
1254
+ ...this.fetchOptions,
1195
1255
  });
1196
1256
  if (!response.ok) {
1197
1257
  const result = await response.json();
@@ -1315,13 +1375,14 @@ export class Client {
1315
1375
  method: "DELETE",
1316
1376
  headers: this.headers,
1317
1377
  signal: AbortSignal.timeout(this.timeout_ms),
1378
+ ...this.fetchOptions,
1318
1379
  });
1319
1380
  if (!response.ok) {
1320
1381
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
1321
1382
  }
1322
1383
  await response.json();
1323
1384
  }
1324
- async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId }) {
1385
+ async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId, metadata, }) {
1325
1386
  let datasetId_ = datasetId;
1326
1387
  if (datasetId_ === undefined && datasetName === undefined) {
1327
1388
  throw new Error("Must provide either datasetName or datasetId");
@@ -1340,12 +1401,14 @@ export class Client {
1340
1401
  outputs,
1341
1402
  created_at: createdAt_?.toISOString(),
1342
1403
  id: exampleId,
1404
+ metadata,
1343
1405
  };
1344
1406
  const response = await this.caller.call(fetch, `${this.apiUrl}/examples`, {
1345
1407
  method: "POST",
1346
1408
  headers: { ...this.headers, "Content-Type": "application/json" },
1347
1409
  body: JSON.stringify(data),
1348
1410
  signal: AbortSignal.timeout(this.timeout_ms),
1411
+ ...this.fetchOptions,
1349
1412
  });
1350
1413
  if (!response.ok) {
1351
1414
  throw new Error(`Failed to create example: ${response.status} ${response.statusText}`);
@@ -1354,7 +1417,7 @@ export class Client {
1354
1417
  return result;
1355
1418
  }
1356
1419
  async createExamples(props) {
1357
- const { inputs, outputs, sourceRunIds, exampleIds, datasetId, datasetName, } = props;
1420
+ const { inputs, outputs, metadata, sourceRunIds, exampleIds, datasetId, datasetName, } = props;
1358
1421
  let datasetId_ = datasetId;
1359
1422
  if (datasetId_ === undefined && datasetName === undefined) {
1360
1423
  throw new Error("Must provide either datasetName or datasetId");
@@ -1371,6 +1434,7 @@ export class Client {
1371
1434
  dataset_id: datasetId_,
1372
1435
  inputs: input,
1373
1436
  outputs: outputs ? outputs[idx] : undefined,
1437
+ metadata: metadata ? metadata[idx] : undefined,
1374
1438
  id: exampleIds ? exampleIds[idx] : undefined,
1375
1439
  source_run_id: sourceRunIds ? sourceRunIds[idx] : undefined,
1376
1440
  };
@@ -1380,6 +1444,7 @@ export class Client {
1380
1444
  headers: { ...this.headers, "Content-Type": "application/json" },
1381
1445
  body: JSON.stringify(formattedExamples),
1382
1446
  signal: AbortSignal.timeout(this.timeout_ms),
1447
+ ...this.fetchOptions,
1383
1448
  });
1384
1449
  if (!response.ok) {
1385
1450
  throw new Error(`Failed to create examples: ${response.status} ${response.statusText}`);
@@ -1449,6 +1514,7 @@ export class Client {
1449
1514
  method: "DELETE",
1450
1515
  headers: this.headers,
1451
1516
  signal: AbortSignal.timeout(this.timeout_ms),
1517
+ ...this.fetchOptions,
1452
1518
  });
1453
1519
  if (!response.ok) {
1454
1520
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1462,6 +1528,7 @@ export class Client {
1462
1528
  headers: { ...this.headers, "Content-Type": "application/json" },
1463
1529
  body: JSON.stringify(update),
1464
1530
  signal: AbortSignal.timeout(this.timeout_ms),
1531
+ ...this.fetchOptions,
1465
1532
  });
1466
1533
  if (!response.ok) {
1467
1534
  throw new Error(`Failed to update example ${exampleId}: ${response.status} ${response.statusText}`);
@@ -1531,6 +1598,7 @@ export class Client {
1531
1598
  headers: { ...this.headers, "Content-Type": "application/json" },
1532
1599
  body: JSON.stringify(feedback),
1533
1600
  signal: AbortSignal.timeout(this.timeout_ms),
1601
+ ...this.fetchOptions,
1534
1602
  });
1535
1603
  await raiseForStatus(response, "create feedback");
1536
1604
  return feedback;
@@ -1555,6 +1623,7 @@ export class Client {
1555
1623
  headers: { ...this.headers, "Content-Type": "application/json" },
1556
1624
  body: JSON.stringify(feedbackUpdate),
1557
1625
  signal: AbortSignal.timeout(this.timeout_ms),
1626
+ ...this.fetchOptions,
1558
1627
  });
1559
1628
  await raiseForStatus(response, "update feedback");
1560
1629
  }
@@ -1571,6 +1640,7 @@ export class Client {
1571
1640
  method: "DELETE",
1572
1641
  headers: this.headers,
1573
1642
  signal: AbortSignal.timeout(this.timeout_ms),
1643
+ ...this.fetchOptions,
1574
1644
  });
1575
1645
  if (!response.ok) {
1576
1646
  throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
@@ -1635,6 +1705,7 @@ export class Client {
1635
1705
  headers: { ...this.headers, "Content-Type": "application/json" },
1636
1706
  body: JSON.stringify(body),
1637
1707
  signal: AbortSignal.timeout(this.timeout_ms),
1708
+ ...this.fetchOptions,
1638
1709
  });
1639
1710
  const result = await response.json();
1640
1711
  return result;
@@ -1,4 +1,42 @@
1
1
  import { Example, Run, ScoreType, ValueType } from "../schemas.js";
2
+ /**
3
+ * Represents a categorical class.
4
+ */
5
+ export type Category = {
6
+ /**
7
+ * The value of the category.
8
+ */
9
+ value?: number;
10
+ /**
11
+ * The label of the category.
12
+ */
13
+ label: string;
14
+ };
15
+ /**
16
+ * Configuration for feedback.
17
+ */
18
+ export type FeedbackConfig = {
19
+ /**
20
+ * The type of feedback.
21
+ * - "continuous": Feedback with a continuous numeric.
22
+ * - "categorical": Feedback with a categorical value (classes)
23
+ * - "freeform": Feedback with a freeform text value (notes).
24
+ */
25
+ type: "continuous" | "categorical" | "freeform";
26
+ /**
27
+ * The minimum value for continuous feedback.
28
+ */
29
+ min?: number;
30
+ /**
31
+ * The maximum value for continuous feedback.
32
+ */
33
+ max?: number;
34
+ /**
35
+ * The categories for categorical feedback.
36
+ * Each category can be a string or an object with additional properties.
37
+ */
38
+ categories?: (Category | Record<string, unknown>)[];
39
+ };
2
40
  /**
3
41
  * Represents the result of an evaluation.
4
42
  */
@@ -38,6 +76,12 @@ export type EvaluationResult = {
38
76
  * the root of the trace.
39
77
  */
40
78
  targetRunId?: string;
79
+ /**
80
+ * The feedback config associated with the evaluation result.
81
+ * If set, this will be used to define how a feedback key
82
+ * should be interpreted.
83
+ */
84
+ feedbackConfig?: FeedbackConfig;
41
85
  };
42
86
  export interface RunEvaluator {
43
87
  evaluateRun(run: Run, example?: Example): Promise<EvaluationResult>;
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.13";
9
+ exports.__version__ = "0.1.18";
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.13";
4
+ export declare const __version__ = "0.1.18";
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.13";
4
+ export const __version__ = "0.1.18";
package/dist/schemas.d.ts CHANGED
@@ -15,7 +15,7 @@ export interface TracerSessionResult extends TracerSession {
15
15
  completion_tokens?: number;
16
16
  last_run_start_time?: number;
17
17
  feedback_stats?: Record<string, unknown>;
18
- reference_dataset_ids?: string[];
18
+ reference_dataset_id?: string;
19
19
  run_facets?: KVMap[];
20
20
  }
21
21
  export type KVMap = Record<string, any>;
@@ -27,6 +27,7 @@ export interface BaseExample {
27
27
  dataset_id: string;
28
28
  inputs: KVMap;
29
29
  outputs?: KVMap;
30
+ metadata?: KVMap;
30
31
  }
31
32
  /**
32
33
  * A run can represent either a trace (root run)
@@ -108,6 +109,8 @@ export interface Run extends BaseRun {
108
109
  first_token_time?: number;
109
110
  /** IDs of parent runs, if multiple exist. */
110
111
  parent_run_ids?: string[];
112
+ /** Whether the run is included in a dataset. */
113
+ in_dataset?: boolean;
111
114
  }
112
115
  export interface RunCreate extends BaseRun {
113
116
  revision_id?: string;
@@ -157,6 +160,7 @@ export interface ExampleUpdate {
157
160
  dataset_id?: string;
158
161
  inputs?: KVMap;
159
162
  outputs?: KVMap;
163
+ metadata?: KVMap;
160
164
  }
161
165
  export interface BaseDataset {
162
166
  name: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isTraceableFunction = exports.traceable = void 0;
3
+ exports.isTraceableFunction = exports.getCurrentRunTree = exports.traceable = void 0;
4
4
  const async_hooks_1 = require("async_hooks");
5
5
  const run_trees_js_1 = require("./run_trees.cjs");
6
6
  const asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
@@ -117,6 +117,24 @@ function traceable(wrappedFunc, config) {
117
117
  return traceableFunc;
118
118
  }
119
119
  exports.traceable = traceable;
120
+ /**
121
+ * Return the current run tree from within a traceable-wrapped function.
122
+ * Will throw an error if called outside of a traceable function.
123
+ *
124
+ * @returns The run tree for the given context.
125
+ */
126
+ function getCurrentRunTree() {
127
+ const runTree = asyncLocalStorage.getStore();
128
+ if (runTree === undefined) {
129
+ throw new Error([
130
+ "Could not get the current run tree.",
131
+ "",
132
+ "Please make sure you are calling this method within a traceable function.",
133
+ ].join("\n"));
134
+ }
135
+ return runTree;
136
+ }
137
+ exports.getCurrentRunTree = getCurrentRunTree;
120
138
  function isTraceableFunction(x
121
139
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
122
140
  ) {
@@ -45,5 +45,12 @@ export type TraceableFunction<Func extends (...args: any[]) => any> = Func exten
45
45
  * a custom LangSmith client instance
46
46
  */
47
47
  export declare function traceable<Func extends (...args: any[]) => any>(wrappedFunc: Func, config?: Partial<RunTreeConfig>): TraceableFunction<Func>;
48
+ /**
49
+ * Return the current run tree from within a traceable-wrapped function.
50
+ * Will throw an error if called outside of a traceable function.
51
+ *
52
+ * @returns The run tree for the given context.
53
+ */
54
+ export declare function getCurrentRunTree(): RunTree;
48
55
  export declare function isTraceableFunction(x: unknown): x is TraceableFunction<any>;
49
56
  export {};
package/dist/traceable.js CHANGED
@@ -113,6 +113,23 @@ export function traceable(wrappedFunc, config) {
113
113
  });
114
114
  return traceableFunc;
115
115
  }
116
+ /**
117
+ * Return the current run tree from within a traceable-wrapped function.
118
+ * Will throw an error if called outside of a traceable function.
119
+ *
120
+ * @returns The run tree for the given context.
121
+ */
122
+ export function getCurrentRunTree() {
123
+ const runTree = asyncLocalStorage.getStore();
124
+ if (runTree === undefined) {
125
+ throw new Error([
126
+ "Could not get the current run tree.",
127
+ "",
128
+ "Please make sure you are calling this method within a traceable function.",
129
+ ].join("\n"));
130
+ }
131
+ return runTree;
132
+ }
116
133
  export function isTraceableFunction(x
117
134
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
135
  ) {
@@ -0,0 +1 @@
1
+ export * from './dist/evaluation/index.js'
package/index.d.cts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/index.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.1.13",
3
+ "version": "0.1.18",
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": [
@@ -8,24 +8,31 @@
8
8
  "client.cjs",
9
9
  "client.js",
10
10
  "client.d.ts",
11
+ "client.d.cts",
11
12
  "run_trees.cjs",
12
13
  "run_trees.js",
13
14
  "run_trees.d.ts",
15
+ "run_trees.d.cts",
14
16
  "traceable.cjs",
15
17
  "traceable.js",
16
18
  "traceable.d.ts",
19
+ "traceable.d.cts",
17
20
  "evaluation.cjs",
18
21
  "evaluation.js",
19
22
  "evaluation.d.ts",
23
+ "evaluation.d.cts",
20
24
  "schemas.cjs",
21
25
  "schemas.js",
22
26
  "schemas.d.ts",
27
+ "schemas.d.cts",
23
28
  "wrappers.cjs",
24
29
  "wrappers.js",
25
30
  "wrappers.d.ts",
31
+ "wrappers.d.cts",
26
32
  "index.cjs",
27
33
  "index.js",
28
- "index.d.ts"
34
+ "index.d.ts",
35
+ "index.d.cts"
29
36
  ],
30
37
  "type": "module",
31
38
  "main": "./dist/index.js",
@@ -102,37 +109,65 @@
102
109
  },
103
110
  "exports": {
104
111
  ".": {
105
- "types": "./index.d.ts",
112
+ "types": {
113
+ "import": "./index.d.ts",
114
+ "require": "./index.d.cts",
115
+ "default": "./index.d.ts"
116
+ },
106
117
  "import": "./index.js",
107
118
  "require": "./index.cjs"
108
119
  },
109
120
  "./client": {
110
- "types": "./client.d.ts",
121
+ "types": {
122
+ "import": "./client.d.ts",
123
+ "require": "./client.d.cts",
124
+ "default": "./client.d.ts"
125
+ },
111
126
  "import": "./client.js",
112
127
  "require": "./client.cjs"
113
128
  },
114
129
  "./run_trees": {
115
- "types": "./run_trees.d.ts",
130
+ "types": {
131
+ "import": "./run_trees.d.ts",
132
+ "require": "./run_trees.d.cts",
133
+ "default": "./run_trees.d.ts"
134
+ },
116
135
  "import": "./run_trees.js",
117
136
  "require": "./run_trees.cjs"
118
137
  },
119
138
  "./traceable": {
120
- "types": "./traceable.d.ts",
139
+ "types": {
140
+ "import": "./traceable.d.ts",
141
+ "require": "./traceable.d.cts",
142
+ "default": "./traceable.d.ts"
143
+ },
121
144
  "import": "./traceable.js",
122
145
  "require": "./traceable.cjs"
123
146
  },
124
147
  "./evaluation": {
125
- "types": "./evaluation.d.ts",
148
+ "types": {
149
+ "import": "./evaluation.d.ts",
150
+ "require": "./evaluation.d.cts",
151
+ "default": "./evaluation.d.ts"
152
+ },
126
153
  "import": "./evaluation.js",
127
154
  "require": "./evaluation.cjs"
128
155
  },
129
156
  "./schemas": {
130
- "types": "./schemas.d.ts",
157
+ "types": {
158
+ "import": "./schemas.d.ts",
159
+ "require": "./schemas.d.cts",
160
+ "default": "./schemas.d.ts"
161
+ },
131
162
  "import": "./schemas.js",
132
163
  "require": "./schemas.cjs"
133
164
  },
134
165
  "./wrappers": {
135
- "types": "./wrappers.d.ts",
166
+ "types": {
167
+ "import": "./wrappers.d.ts",
168
+ "require": "./wrappers.d.cts",
169
+ "default": "./wrappers.d.ts"
170
+ },
136
171
  "import": "./wrappers.js",
137
172
  "require": "./wrappers.cjs"
138
173
  },
@@ -0,0 +1 @@
1
+ export * from './dist/run_trees.js'
package/schemas.d.cts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/schemas.js'
@@ -0,0 +1 @@
1
+ export * from './dist/traceable.js'
package/wrappers.d.cts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/wrappers.js'