langsmith 0.1.43 → 0.1.44

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.js CHANGED
@@ -6,6 +6,7 @@ import { __version__ } from "./index.js";
6
6
  import { assertUuid } from "./utils/_uuid.js";
7
7
  import { warnOnce } from "./utils/warn.js";
8
8
  import { isVersionGreaterOrEqual, parsePromptIdentifier, } from "./utils/prompts.js";
9
+ import { raiseForStatus } from "./utils/error.js";
9
10
  async function mergeRuntimeEnvIntoRunCreates(runs) {
10
11
  const runtimeEnv = await getRuntimeEnvironment();
11
12
  const envVars = getLangChainEnvVarsMetadata();
@@ -46,14 +47,6 @@ const isLocalhost = (url) => {
46
47
  const hostname = strippedUrl.split("/")[0].split(":")[0];
47
48
  return (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1");
48
49
  };
49
- const raiseForStatus = async (response, operation) => {
50
- // consume the response body to release the connection
51
- // https://undici.nodejs.org/#/?id=garbage-collection
52
- const body = await response.text();
53
- if (!response.ok) {
54
- throw new Error(`Failed to ${operation}: ${response.status} ${response.statusText} ${body}`);
55
- }
56
- };
57
50
  async function toArray(iterable) {
58
51
  const result = [];
59
52
  for await (const item of iterable) {
@@ -360,9 +353,7 @@ export class Client {
360
353
  signal: AbortSignal.timeout(this.timeout_ms),
361
354
  ...this.fetchOptions,
362
355
  });
363
- if (!response.ok) {
364
- throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
365
- }
356
+ await raiseForStatus(response, `Failed to fetch ${path}`);
366
357
  return response;
367
358
  }
368
359
  async _get(path, queryParams) {
@@ -382,9 +373,7 @@ export class Client {
382
373
  signal: AbortSignal.timeout(this.timeout_ms),
383
374
  ...this.fetchOptions,
384
375
  });
385
- if (!response.ok) {
386
- throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
387
- }
376
+ await raiseForStatus(response, `Failed to fetch ${path}`);
388
377
  const items = transform
389
378
  ? transform(await response.json())
390
379
  : await response.json();
@@ -501,12 +490,7 @@ export class Client {
501
490
  signal: AbortSignal.timeout(this.timeout_ms),
502
491
  ...this.fetchOptions,
503
492
  });
504
- if (!response.ok) {
505
- // consume the response body to release the connection
506
- // https://undici.nodejs.org/#/?id=garbage-collection
507
- await response.text();
508
- throw new Error("Failed to retrieve server info.");
509
- }
493
+ await raiseForStatus(response, "get server info");
510
494
  return response.json();
511
495
  }
512
496
  async batchEndpointIsSupported() {
@@ -555,7 +539,7 @@ export class Client {
555
539
  signal: AbortSignal.timeout(this.timeout_ms),
556
540
  ...this.fetchOptions,
557
541
  });
558
- await raiseForStatus(response, "create run");
542
+ await raiseForStatus(response, "create run", true);
559
543
  }
560
544
  /**
561
545
  * Batch ingest/upsert multiple runs in the Langsmith system.
@@ -655,7 +639,7 @@ export class Client {
655
639
  signal: AbortSignal.timeout(this.timeout_ms),
656
640
  ...this.fetchOptions,
657
641
  });
658
- await raiseForStatus(response, "batch create run");
642
+ await raiseForStatus(response, "batch create run", true);
659
643
  }
660
644
  async updateRun(runId, run) {
661
645
  assertUuid(runId);
@@ -692,7 +676,7 @@ export class Client {
692
676
  signal: AbortSignal.timeout(this.timeout_ms),
693
677
  ...this.fetchOptions,
694
678
  });
695
- await raiseForStatus(response, "update run");
679
+ await raiseForStatus(response, "update run", true);
696
680
  }
697
681
  async readRun(runId, { loadChildRuns } = { loadChildRuns: false }) {
698
682
  assertUuid(runId);
@@ -985,7 +969,7 @@ export class Client {
985
969
  signal: AbortSignal.timeout(this.timeout_ms),
986
970
  ...this.fetchOptions,
987
971
  });
988
- await raiseForStatus(response, "unshare run");
972
+ await raiseForStatus(response, "unshare run", true);
989
973
  }
990
974
  async readRunSharedLink(runId) {
991
975
  assertUuid(runId);
@@ -1070,7 +1054,7 @@ export class Client {
1070
1054
  signal: AbortSignal.timeout(this.timeout_ms),
1071
1055
  ...this.fetchOptions,
1072
1056
  });
1073
- await raiseForStatus(response, "unshare dataset");
1057
+ await raiseForStatus(response, "unshare dataset", true);
1074
1058
  }
1075
1059
  async readSharedDataset(shareToken) {
1076
1060
  assertUuid(shareToken);
@@ -1083,6 +1067,46 @@ export class Client {
1083
1067
  const dataset = await response.json();
1084
1068
  return dataset;
1085
1069
  }
1070
+ /**
1071
+ * Get shared examples.
1072
+ *
1073
+ * @param {string} shareToken The share token to get examples for. A share token is the UUID (or LangSmith URL, including UUID) generated when explicitly marking an example as public.
1074
+ * @param {Object} [options] Additional options for listing the examples.
1075
+ * @param {string[] | undefined} [options.exampleIds] A list of example IDs to filter by.
1076
+ * @returns {Promise<Example[]>} The shared examples.
1077
+ */
1078
+ async listSharedExamples(shareToken, options) {
1079
+ const params = {};
1080
+ if (options?.exampleIds) {
1081
+ params.id = options.exampleIds;
1082
+ }
1083
+ const urlParams = new URLSearchParams();
1084
+ Object.entries(params).forEach(([key, value]) => {
1085
+ if (Array.isArray(value)) {
1086
+ value.forEach((v) => urlParams.append(key, v));
1087
+ }
1088
+ else {
1089
+ urlParams.append(key, value);
1090
+ }
1091
+ });
1092
+ const response = await this.caller.call(fetch, `${this.apiUrl}/public/${shareToken}/examples?${urlParams.toString()}`, {
1093
+ method: "GET",
1094
+ headers: this.headers,
1095
+ signal: AbortSignal.timeout(this.timeout_ms),
1096
+ ...this.fetchOptions,
1097
+ });
1098
+ const result = await response.json();
1099
+ if (!response.ok) {
1100
+ if ("detail" in result) {
1101
+ throw new Error(`Failed to list shared examples.\nStatus: ${response.status}\nMessage: ${result.detail.join("\n")}`);
1102
+ }
1103
+ throw new Error(`Failed to list shared examples: ${response.status} ${response.statusText}`);
1104
+ }
1105
+ return result.map((example) => ({
1106
+ ...example,
1107
+ _hostUrl: this.getHostUrl(),
1108
+ }));
1109
+ }
1086
1110
  async createProject({ projectName, description = null, metadata = null, upsert = false, projectExtra = null, referenceDatasetId = null, }) {
1087
1111
  const upsert_ = upsert ? `?upsert=true` : "";
1088
1112
  const endpoint = `${this.apiUrl}/sessions${upsert_}`;
@@ -1105,10 +1129,8 @@ export class Client {
1105
1129
  signal: AbortSignal.timeout(this.timeout_ms),
1106
1130
  ...this.fetchOptions,
1107
1131
  });
1132
+ await raiseForStatus(response, "create project");
1108
1133
  const result = await response.json();
1109
- if (!response.ok) {
1110
- throw new Error(`Failed to create session ${projectName}: ${response.status} ${response.statusText}`);
1111
- }
1112
1134
  return result;
1113
1135
  }
1114
1136
  async updateProject(projectId, { name = null, description = null, metadata = null, projectExtra = null, endTime = null, }) {
@@ -1130,10 +1152,8 @@ export class Client {
1130
1152
  signal: AbortSignal.timeout(this.timeout_ms),
1131
1153
  ...this.fetchOptions,
1132
1154
  });
1155
+ await raiseForStatus(response, "update project");
1133
1156
  const result = await response.json();
1134
- if (!response.ok) {
1135
- throw new Error(`Failed to update project ${projectId}: ${response.status} ${response.statusText}`);
1136
- }
1137
1157
  return result;
1138
1158
  }
1139
1159
  async hasProject({ projectId, projectName, }) {
@@ -1289,7 +1309,7 @@ export class Client {
1289
1309
  signal: AbortSignal.timeout(this.timeout_ms),
1290
1310
  ...this.fetchOptions,
1291
1311
  });
1292
- await raiseForStatus(response, `delete session ${projectId_} (${projectName})`);
1312
+ await raiseForStatus(response, `delete session ${projectId_} (${projectName})`, true);
1293
1313
  }
1294
1314
  async uploadCsv({ csvFile, fileName, inputKeys, outputKeys, description, dataType, name, }) {
1295
1315
  const url = `${this.apiUrl}/datasets/upload`;
@@ -1317,13 +1337,7 @@ export class Client {
1317
1337
  signal: AbortSignal.timeout(this.timeout_ms),
1318
1338
  ...this.fetchOptions,
1319
1339
  });
1320
- if (!response.ok) {
1321
- const result = await response.json();
1322
- if (result.detail && result.detail.includes("already exists")) {
1323
- throw new Error(`Dataset ${fileName} already exists`);
1324
- }
1325
- throw new Error(`Failed to upload CSV: ${response.status} ${response.statusText}`);
1326
- }
1340
+ await raiseForStatus(response, "upload CSV");
1327
1341
  const result = await response.json();
1328
1342
  return result;
1329
1343
  }
@@ -1348,13 +1362,7 @@ export class Client {
1348
1362
  signal: AbortSignal.timeout(this.timeout_ms),
1349
1363
  ...this.fetchOptions,
1350
1364
  });
1351
- if (!response.ok) {
1352
- const result = await response.json();
1353
- if (result.detail && result.detail.includes("already exists")) {
1354
- throw new Error(`Dataset ${name} already exists`);
1355
- }
1356
- throw new Error(`Failed to create dataset ${response.status} ${response.statusText}`);
1357
- }
1365
+ await raiseForStatus(response, "create dataset");
1358
1366
  const result = await response.json();
1359
1367
  return result;
1360
1368
  }
@@ -1483,9 +1491,7 @@ export class Client {
1483
1491
  signal: AbortSignal.timeout(this.timeout_ms),
1484
1492
  ...this.fetchOptions,
1485
1493
  });
1486
- if (!response.ok) {
1487
- throw new Error(`Failed to update dataset ${_datasetId}: ${response.status} ${response.statusText}`);
1488
- }
1494
+ await raiseForStatus(response, "update dataset");
1489
1495
  return (await response.json());
1490
1496
  }
1491
1497
  async deleteDataset({ datasetId, datasetName, }) {
@@ -1511,9 +1517,7 @@ export class Client {
1511
1517
  signal: AbortSignal.timeout(this.timeout_ms),
1512
1518
  ...this.fetchOptions,
1513
1519
  });
1514
- if (!response.ok) {
1515
- throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
1516
- }
1520
+ await raiseForStatus(response, `delete ${path}`);
1517
1521
  await response.json();
1518
1522
  }
1519
1523
  async indexDataset({ datasetId, datasetName, tag, }) {
@@ -1539,9 +1543,7 @@ export class Client {
1539
1543
  signal: AbortSignal.timeout(this.timeout_ms),
1540
1544
  ...this.fetchOptions,
1541
1545
  });
1542
- if (!response.ok) {
1543
- throw new Error(`Failed to index dataset ${datasetId_}: ${response.status} ${response.statusText}`);
1544
- }
1546
+ await raiseForStatus(response, "index dataset");
1545
1547
  await response.json();
1546
1548
  }
1547
1549
  /**
@@ -1580,9 +1582,7 @@ export class Client {
1580
1582
  signal: AbortSignal.timeout(this.timeout_ms),
1581
1583
  ...this.fetchOptions,
1582
1584
  });
1583
- if (!response.ok) {
1584
- throw new Error(`Failed to fetch similar examples: ${response.status} ${response.statusText}`);
1585
- }
1585
+ await raiseForStatus(response, "fetch similar examples");
1586
1586
  const result = await response.json();
1587
1587
  return result["examples"];
1588
1588
  }
@@ -1615,9 +1615,7 @@ export class Client {
1615
1615
  signal: AbortSignal.timeout(this.timeout_ms),
1616
1616
  ...this.fetchOptions,
1617
1617
  });
1618
- if (!response.ok) {
1619
- throw new Error(`Failed to create example: ${response.status} ${response.statusText}`);
1620
- }
1618
+ await raiseForStatus(response, "create example");
1621
1619
  const result = await response.json();
1622
1620
  return result;
1623
1621
  }
@@ -1652,9 +1650,7 @@ export class Client {
1652
1650
  signal: AbortSignal.timeout(this.timeout_ms),
1653
1651
  ...this.fetchOptions,
1654
1652
  });
1655
- if (!response.ok) {
1656
- throw new Error(`Failed to create examples: ${response.status} ${response.statusText}`);
1657
- }
1653
+ await raiseForStatus(response, "create examples");
1658
1654
  const result = await response.json();
1659
1655
  return result;
1660
1656
  }
@@ -1747,9 +1743,7 @@ export class Client {
1747
1743
  signal: AbortSignal.timeout(this.timeout_ms),
1748
1744
  ...this.fetchOptions,
1749
1745
  });
1750
- if (!response.ok) {
1751
- throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
1752
- }
1746
+ await raiseForStatus(response, `delete ${path}`);
1753
1747
  await response.json();
1754
1748
  }
1755
1749
  async updateExample(exampleId, update) {
@@ -1761,9 +1755,7 @@ export class Client {
1761
1755
  signal: AbortSignal.timeout(this.timeout_ms),
1762
1756
  ...this.fetchOptions,
1763
1757
  });
1764
- if (!response.ok) {
1765
- throw new Error(`Failed to update example ${exampleId}: ${response.status} ${response.statusText}`);
1766
- }
1758
+ await raiseForStatus(response, "update example");
1767
1759
  const result = await response.json();
1768
1760
  return result;
1769
1761
  }
@@ -1775,9 +1767,7 @@ export class Client {
1775
1767
  signal: AbortSignal.timeout(this.timeout_ms),
1776
1768
  ...this.fetchOptions,
1777
1769
  });
1778
- if (!response.ok) {
1779
- throw new Error(`Failed to update examples: ${response.status} ${response.statusText}`);
1780
- }
1770
+ await raiseForStatus(response, "update examples");
1781
1771
  const result = await response.json();
1782
1772
  return result;
1783
1773
  }
@@ -1840,7 +1830,7 @@ export class Client {
1840
1830
  signal: AbortSignal.timeout(this.timeout_ms),
1841
1831
  ...this.fetchOptions,
1842
1832
  });
1843
- await raiseForStatus(response, "update dataset splits");
1833
+ await raiseForStatus(response, "update dataset splits", true);
1844
1834
  }
1845
1835
  /**
1846
1836
  * @deprecated This method is deprecated and will be removed in future LangSmith versions, use `evaluate` from `langsmith/evaluation` instead.
@@ -1906,7 +1896,7 @@ export class Client {
1906
1896
  signal: AbortSignal.timeout(this.timeout_ms),
1907
1897
  ...this.fetchOptions,
1908
1898
  });
1909
- await raiseForStatus(response, "create feedback");
1899
+ await raiseForStatus(response, "create feedback", true);
1910
1900
  return feedback;
1911
1901
  }
1912
1902
  async updateFeedback(feedbackId, { score, value, correction, comment, }) {
@@ -1931,7 +1921,7 @@ export class Client {
1931
1921
  signal: AbortSignal.timeout(this.timeout_ms),
1932
1922
  ...this.fetchOptions,
1933
1923
  });
1934
- await raiseForStatus(response, "update feedback");
1924
+ await raiseForStatus(response, "update feedback", true);
1935
1925
  }
1936
1926
  async readFeedback(feedbackId) {
1937
1927
  assertUuid(feedbackId);
@@ -1948,9 +1938,7 @@ export class Client {
1948
1938
  signal: AbortSignal.timeout(this.timeout_ms),
1949
1939
  ...this.fetchOptions,
1950
1940
  });
1951
- if (!response.ok) {
1952
- throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
1953
- }
1941
+ await raiseForStatus(response, `delete ${path}`);
1954
1942
  await response.json();
1955
1943
  }
1956
1944
  async *listFeedback({ runIds, feedbackKeys, feedbackSourceTypes, } = {}) {
@@ -2143,9 +2131,7 @@ export class Client {
2143
2131
  signal: AbortSignal.timeout(this.timeout_ms),
2144
2132
  ...this.fetchOptions,
2145
2133
  });
2146
- if (!response.ok) {
2147
- throw new Error(`Failed to ${like ? "like" : "unlike"} prompt: ${response.status} ${await response.text()}`);
2148
- }
2134
+ await raiseForStatus(response, `${like ? "like" : "unlike"} prompt`);
2149
2135
  return await response.json();
2150
2136
  }
2151
2137
  async _getPromptUrl(promptIdentifier) {
@@ -2209,9 +2195,7 @@ export class Client {
2209
2195
  if (response.status === 404) {
2210
2196
  return null;
2211
2197
  }
2212
- if (!response.ok) {
2213
- throw new Error(`Failed to get prompt: ${response.status} ${await response.text()}`);
2214
- }
2198
+ await raiseForStatus(response, "get prompt");
2215
2199
  const result = await response.json();
2216
2200
  if (result.repo) {
2217
2201
  return result.repo;
@@ -2246,9 +2230,7 @@ export class Client {
2246
2230
  signal: AbortSignal.timeout(this.timeout_ms),
2247
2231
  ...this.fetchOptions,
2248
2232
  });
2249
- if (!response.ok) {
2250
- throw new Error(`Failed to create prompt: ${response.status} ${await response.text()}`);
2251
- }
2233
+ await raiseForStatus(response, "create prompt");
2252
2234
  const { repo } = await response.json();
2253
2235
  return repo;
2254
2236
  }
@@ -2271,9 +2253,7 @@ export class Client {
2271
2253
  signal: AbortSignal.timeout(this.timeout_ms),
2272
2254
  ...this.fetchOptions,
2273
2255
  });
2274
- if (!response.ok) {
2275
- throw new Error(`Failed to create commit: ${response.status} ${await response.text()}`);
2276
- }
2256
+ await raiseForStatus(response, "create commit");
2277
2257
  const result = await response.json();
2278
2258
  return this._getPromptUrl(`${owner}/${promptName}${result.commit_hash ? `:${result.commit_hash}` : ""}`);
2279
2259
  }
@@ -2310,9 +2290,7 @@ export class Client {
2310
2290
  signal: AbortSignal.timeout(this.timeout_ms),
2311
2291
  ...this.fetchOptions,
2312
2292
  });
2313
- if (!response.ok) {
2314
- throw new Error(`HTTP Error: ${response.status} - ${await response.text()}`);
2315
- }
2293
+ await raiseForStatus(response, "update prompt");
2316
2294
  return response.json();
2317
2295
  }
2318
2296
  async deletePrompt(promptIdentifier) {
@@ -2351,9 +2329,7 @@ export class Client {
2351
2329
  signal: AbortSignal.timeout(this.timeout_ms),
2352
2330
  ...this.fetchOptions,
2353
2331
  });
2354
- if (!response.ok) {
2355
- throw new Error(`Failed to pull prompt commit: ${response.status} ${response.statusText}`);
2356
- }
2332
+ await raiseForStatus(response, "pull prompt commit");
2357
2333
  const result = await response.json();
2358
2334
  return {
2359
2335
  owner,
@@ -2406,4 +2382,85 @@ export class Client {
2406
2382
  });
2407
2383
  return url;
2408
2384
  }
2385
+ /**
2386
+ * Clone a public dataset to your own langsmith tenant.
2387
+ * This operation is idempotent. If you already have a dataset with the given name,
2388
+ * this function will do nothing.
2389
+
2390
+ * @param {string} tokenOrUrl The token of the public dataset to clone.
2391
+ * @param {Object} [options] Additional options for cloning the dataset.
2392
+ * @param {string} [options.sourceApiUrl] The URL of the langsmith server where the data is hosted. Defaults to the API URL of your current client.
2393
+ * @param {string} [options.datasetName] The name of the dataset to create in your tenant. Defaults to the name of the public dataset.
2394
+ * @returns {Promise<void>}
2395
+ */
2396
+ async clonePublicDataset(tokenOrUrl, options = {}) {
2397
+ const { sourceApiUrl = this.apiUrl, datasetName } = options;
2398
+ const [parsedApiUrl, tokenUuid] = this.parseTokenOrUrl(tokenOrUrl, sourceApiUrl);
2399
+ const sourceClient = new Client({
2400
+ apiUrl: parsedApiUrl,
2401
+ // Placeholder API key not needed anymore in most cases, but
2402
+ // some private deployments may have API key-based rate limiting
2403
+ // that would cause this to fail if we provide no value.
2404
+ apiKey: "placeholder",
2405
+ });
2406
+ const ds = await sourceClient.readSharedDataset(tokenUuid);
2407
+ const finalDatasetName = datasetName || ds.name;
2408
+ try {
2409
+ if (await this.hasDataset({ datasetId: finalDatasetName })) {
2410
+ console.log(`Dataset ${finalDatasetName} already exists in your tenant. Skipping.`);
2411
+ return;
2412
+ }
2413
+ }
2414
+ catch (_) {
2415
+ // `.hasDataset` will throw an error if the dataset does not exist.
2416
+ // no-op in that case
2417
+ }
2418
+ // Fetch examples first, then create the dataset
2419
+ const examples = await sourceClient.listSharedExamples(tokenUuid);
2420
+ const dataset = await this.createDataset(finalDatasetName, {
2421
+ description: ds.description,
2422
+ dataType: ds.data_type || "kv",
2423
+ inputsSchema: ds.inputs_schema_definition ?? undefined,
2424
+ outputsSchema: ds.outputs_schema_definition ?? undefined,
2425
+ });
2426
+ try {
2427
+ await this.createExamples({
2428
+ inputs: examples.map((e) => e.inputs),
2429
+ outputs: examples.flatMap((e) => (e.outputs ? [e.outputs] : [])),
2430
+ datasetId: dataset.id,
2431
+ });
2432
+ }
2433
+ catch (e) {
2434
+ console.error(`An error occurred while creating dataset ${finalDatasetName}. ` +
2435
+ "You should delete it manually.");
2436
+ throw e;
2437
+ }
2438
+ }
2439
+ parseTokenOrUrl(urlOrToken, apiUrl, numParts = 2, kind = "dataset") {
2440
+ // Try parsing as UUID
2441
+ try {
2442
+ assertUuid(urlOrToken); // Will throw if it's not a UUID.
2443
+ return [apiUrl, urlOrToken];
2444
+ }
2445
+ catch (_) {
2446
+ // no-op if it's not a uuid
2447
+ }
2448
+ // Parse as URL
2449
+ try {
2450
+ const parsedUrl = new URL(urlOrToken);
2451
+ const pathParts = parsedUrl.pathname
2452
+ .split("/")
2453
+ .filter((part) => part !== "");
2454
+ if (pathParts.length >= numParts) {
2455
+ const tokenUuid = pathParts[pathParts.length - numParts];
2456
+ return [apiUrl, tokenUuid];
2457
+ }
2458
+ else {
2459
+ throw new Error(`Invalid public ${kind} URL: ${urlOrToken}`);
2460
+ }
2461
+ }
2462
+ catch (error) {
2463
+ throw new Error(`Invalid public ${kind} URL or token: ${urlOrToken}`);
2464
+ }
2465
+ }
2409
2466
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.evaluate = void 0;
3
+ exports._ExperimentManager = exports.evaluate = void 0;
4
4
  const index_js_1 = require("../index.cjs");
5
5
  const langchain_js_1 = require("../langchain.cjs");
6
6
  const traceable_js_1 = require("../traceable.cjs");
@@ -232,17 +232,40 @@ class _ExperimentManager {
232
232
  }
233
233
  return projectMetadata;
234
234
  }
235
- async _getProject(firstExample) {
235
+ async _createProject(firstExample, projectMetadata) {
236
+ // Create the project, updating the experimentName until we find a unique one.
236
237
  let project;
237
- if (!this._experiment) {
238
+ const originalExperimentName = this._experimentName;
239
+ for (let i = 0; i < 10; i++) {
238
240
  try {
239
- const projectMetadata = await this._getExperimentMetadata();
240
241
  project = await this.client.createProject({
241
- projectName: this.experimentName,
242
+ projectName: this._experimentName,
242
243
  referenceDatasetId: firstExample.dataset_id,
243
244
  metadata: projectMetadata,
244
245
  description: this._description,
245
246
  });
247
+ return project;
248
+ }
249
+ catch (e) {
250
+ // Naming collision
251
+ if (e?.name === "LangSmithConflictError") {
252
+ const ent = (0, uuid_1.v4)().slice(0, 6);
253
+ this._experimentName = `${originalExperimentName}-${ent}`;
254
+ }
255
+ else {
256
+ throw e;
257
+ }
258
+ }
259
+ }
260
+ throw new Error("Could not generate a unique experiment name within 10 attempts." +
261
+ " Please try again with a different name.");
262
+ }
263
+ async _getProject(firstExample) {
264
+ let project;
265
+ if (!this._experiment) {
266
+ try {
267
+ const projectMetadata = await this._getExperimentMetadata();
268
+ project = await this._createProject(firstExample, projectMetadata);
246
269
  this._experiment = project;
247
270
  }
248
271
  catch (e) {
@@ -554,6 +577,7 @@ class _ExperimentManager {
554
577
  });
555
578
  }
556
579
  }
580
+ exports._ExperimentManager = _ExperimentManager;
557
581
  /**
558
582
  * Represents the results of an evaluate() call.
559
583
  * This class provides an iterator interface to iterate over the experiment results
@@ -88,7 +88,7 @@ interface ExperimentResultRow {
88
88
  * Supports lazily running predictions and evaluations in parallel to facilitate
89
89
  * result streaming and early debugging.
90
90
  */
91
- declare class _ExperimentManager {
91
+ export declare class _ExperimentManager {
92
92
  _data?: DataT;
93
93
  _runs?: AsyncGenerator<Run>;
94
94
  _evaluationResults?: AsyncGenerator<EvaluationResults>;
@@ -110,6 +110,7 @@ declare class _ExperimentManager {
110
110
  constructor(args: _ExperimentManagerArgs);
111
111
  _getExperiment(): TracerSession;
112
112
  _getExperimentMetadata(): Promise<KVMap>;
113
+ _createProject(firstExample: Example, projectMetadata: KVMap): Promise<TracerSession>;
113
114
  _getProject(firstExample: Example): Promise<TracerSession>;
114
115
  protected _printExperimentStart(): Promise<void>;
115
116
  start(): Promise<_ExperimentManager>;
@@ -23,7 +23,7 @@ target, options) {
23
23
  * Supports lazily running predictions and evaluations in parallel to facilitate
24
24
  * result streaming and early debugging.
25
25
  */
26
- class _ExperimentManager {
26
+ export class _ExperimentManager {
27
27
  get experimentName() {
28
28
  if (this._experimentName) {
29
29
  return this._experimentName;
@@ -228,17 +228,40 @@ class _ExperimentManager {
228
228
  }
229
229
  return projectMetadata;
230
230
  }
231
- async _getProject(firstExample) {
231
+ async _createProject(firstExample, projectMetadata) {
232
+ // Create the project, updating the experimentName until we find a unique one.
232
233
  let project;
233
- if (!this._experiment) {
234
+ const originalExperimentName = this._experimentName;
235
+ for (let i = 0; i < 10; i++) {
234
236
  try {
235
- const projectMetadata = await this._getExperimentMetadata();
236
237
  project = await this.client.createProject({
237
- projectName: this.experimentName,
238
+ projectName: this._experimentName,
238
239
  referenceDatasetId: firstExample.dataset_id,
239
240
  metadata: projectMetadata,
240
241
  description: this._description,
241
242
  });
243
+ return project;
244
+ }
245
+ catch (e) {
246
+ // Naming collision
247
+ if (e?.name === "LangSmithConflictError") {
248
+ const ent = uuidv4().slice(0, 6);
249
+ this._experimentName = `${originalExperimentName}-${ent}`;
250
+ }
251
+ else {
252
+ throw e;
253
+ }
254
+ }
255
+ }
256
+ throw new Error("Could not generate a unique experiment name within 10 attempts." +
257
+ " Please try again with a different name.");
258
+ }
259
+ async _getProject(firstExample) {
260
+ let project;
261
+ if (!this._experiment) {
262
+ try {
263
+ const projectMetadata = await this._getExperimentMetadata();
264
+ project = await this._createProject(firstExample, projectMetadata);
242
265
  this._experiment = project;
243
266
  }
244
267
  catch (e) {
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.43";
9
+ exports.__version__ = "0.1.44";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Client } from "./client.js";
1
+ export { Client, type ClientConfig } from "./client.js";
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, RetrieverOutput, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
- export declare const __version__ = "0.1.43";
4
+ export declare const __version__ = "0.1.44";
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.43";
4
+ export const __version__ = "0.1.44";
package/dist/schemas.d.ts CHANGED
@@ -189,6 +189,8 @@ export interface BaseDataset {
189
189
  description: string;
190
190
  tenant_id: string;
191
191
  data_type?: DataType;
192
+ inputs_schema_definition?: KVMap;
193
+ outputs_schema_definition?: KVMap;
192
194
  }
193
195
  export interface Dataset extends BaseDataset {
194
196
  id: string;