langsmith 0.8.4 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.cjs CHANGED
@@ -648,6 +648,12 @@ class Client {
648
648
  writable: true,
649
649
  value: void 0
650
650
  });
651
+ Object.defineProperty(this, "_stainlessVersionChecked", {
652
+ enumerable: true,
653
+ configurable: true,
654
+ writable: true,
655
+ value: false
656
+ });
651
657
  Object.defineProperty(this, "manualFlushMode", {
652
658
  enumerable: true,
653
659
  configurable: true,
@@ -975,27 +981,37 @@ class Client {
975
981
  return needsV1Prefix ? `/v1/platform/${path}` : `/platform/${path}`;
976
982
  }
977
983
  get evaluators() {
984
+ this._checkStainlessVersion();
978
985
  return this.openAPIClient.onlineEvaluators;
979
986
  }
980
987
  get runs() {
988
+ this._checkStainlessVersion();
981
989
  return this.openAPIClient.runs;
982
990
  }
983
991
  /** Access the v2 sandboxes resource (registries, snapshots, boxes). */
984
992
  get sandboxes() {
993
+ this._checkStainlessVersion();
985
994
  return this.openAPIClient.sandboxes;
986
995
  }
987
996
  /** Access the v2 datasets resource (experimentRuns, etc.). */
988
997
  get datasets() {
998
+ this._checkStainlessVersion();
989
999
  return this.openAPIClient.datasets;
990
1000
  }
991
1001
  /** Access the threads resource (query, stats, listTraces). */
992
1002
  get threads() {
1003
+ this._checkStainlessVersion();
993
1004
  return this.openAPIClient.threads;
994
1005
  }
995
1006
  /** Access the traces resource (query, listRuns). */
996
1007
  get traces() {
1008
+ this._checkStainlessVersion();
997
1009
  return this.openAPIClient.traces;
998
1010
  }
1011
+ /** Access the public shared-run resource. */
1012
+ get public() {
1013
+ return this.openAPIClient.public;
1014
+ }
999
1015
  async processInputs(inputs) {
1000
1016
  if (this.hideInputs === false) {
1001
1017
  return inputs;
@@ -1482,15 +1498,26 @@ class Client {
1482
1498
  }
1483
1499
  return json;
1484
1500
  }
1501
+ _checkStainlessVersion() {
1502
+ if (this._stainlessVersionChecked)
1503
+ return;
1504
+ this._stainlessVersionChecked = true;
1505
+ this._ensureServerInfo()
1506
+ .then((serverInfo) => {
1507
+ if (serverInfo?.version) {
1508
+ _checkBackendVersion(serverInfo.version);
1509
+ }
1510
+ })
1511
+ .catch(() => {
1512
+ // _ensureServerInfo handles and logs its own errors
1513
+ });
1514
+ }
1485
1515
  async _ensureServerInfo() {
1486
1516
  if (this._getServerInfoPromise === undefined) {
1487
1517
  this._getServerInfoPromise = (async () => {
1488
1518
  if (this._serverInfo === undefined) {
1489
1519
  try {
1490
1520
  this._serverInfo = await this._getServerInfo();
1491
- if (this._serverInfo?.version) {
1492
- _checkBackendVersion(this._serverInfo.version);
1493
- }
1494
1521
  }
1495
1522
  catch (e) {
1496
1523
  console.warn(`[LANGSMITH]: Failed to fetch info on supported operations. Falling back to batch operations and default limits. Info: ${e.status ?? "Unspecified status code"} ${e.message}`);
@@ -1506,6 +1533,10 @@ class Client {
1506
1533
  return serverInfo;
1507
1534
  });
1508
1535
  }
1536
+ async _supportsSDBQuery() {
1537
+ const serverInfo = await this._ensureServerInfo();
1538
+ return serverInfo.instance_flags?.sdb_query_enabled === true;
1539
+ }
1509
1540
  async _getSettings() {
1510
1541
  if (!this.settings) {
1511
1542
  this.settings = this._get("/settings");
@@ -2444,6 +2475,9 @@ class Client {
2444
2475
  ...(await Promise.all(projectNames.map((name) => this.readProject({ projectName: name }).then((project) => project.id)))),
2445
2476
  ];
2446
2477
  }
2478
+ if (projectIds_.length === 0) {
2479
+ throw new Error("At least one of projectNames or projectIds must be provided.");
2480
+ }
2447
2481
  const payload = {
2448
2482
  id,
2449
2483
  trace,
@@ -3827,7 +3861,7 @@ class Client {
3827
3861
  }
3828
3862
  return results_;
3829
3863
  }
3830
- async _logEvaluationFeedback(evaluatorResponse, run, sourceInfo) {
3864
+ async _logEvaluationFeedback(evaluatorResponse, run, sourceInfo, sessionId) {
3831
3865
  const evalResults = this._selectEvalResults(evaluatorResponse);
3832
3866
  const feedbacks = [];
3833
3867
  for (const res of evalResults) {
@@ -3851,14 +3885,20 @@ class Client {
3851
3885
  sourceRunId: res.sourceRunId,
3852
3886
  feedbackConfig: res.feedbackConfig,
3853
3887
  feedbackSourceType: "model",
3854
- sessionId: run?.session_id,
3888
+ sessionId: run?.session_id ?? sessionId,
3855
3889
  startTime: run?.start_time,
3856
3890
  }));
3857
3891
  }
3858
3892
  return [evalResults, feedbacks];
3859
3893
  }
3860
- async logEvaluationFeedback(evaluatorResponse, run, sourceInfo) {
3861
- const [results] = await this._logEvaluationFeedback(evaluatorResponse, run, sourceInfo);
3894
+ async logEvaluationFeedback(evaluatorResponseOrParams, run, sourceInfo, sessionId) {
3895
+ if (evaluatorResponseOrParams != null &&
3896
+ typeof evaluatorResponseOrParams === "object" &&
3897
+ "evaluatorResponse" in evaluatorResponseOrParams) {
3898
+ const [results] = await this._logEvaluationFeedback(evaluatorResponseOrParams.evaluatorResponse, evaluatorResponseOrParams.run, evaluatorResponseOrParams.sourceInfo, evaluatorResponseOrParams.projectId);
3899
+ return results;
3900
+ }
3901
+ const [results] = await this._logEvaluationFeedback(evaluatorResponseOrParams, run, sourceInfo, sessionId);
3862
3902
  return results;
3863
3903
  }
3864
3904
  /**
package/dist/client.d.ts CHANGED
@@ -9,6 +9,7 @@ import { Sandboxes } from "./_openapi_client/resources/sandboxes/sandboxes.js";
9
9
  import { Datasets } from "./_openapi_client/resources/datasets/datasets.js";
10
10
  import { Threads } from "./_openapi_client/resources/threads.js";
11
11
  import { Traces } from "./_openapi_client/resources/traces.js";
12
+ import { Public } from "./_openapi_client/resources/public/public.js";
12
13
  import { PromptCache } from "./utils/prompt_cache/index.js";
13
14
  import { ProfileAuth } from "./utils/profiles.js";
14
15
  export interface ClientConfig {
@@ -461,6 +462,7 @@ export declare class Client implements LangSmithTracingClientInterface {
461
462
  private traceBatchConcurrency;
462
463
  private _serverInfo;
463
464
  private _getServerInfoPromise?;
465
+ private _stainlessVersionChecked;
464
466
  private manualFlushMode;
465
467
  private _serializeWorker?;
466
468
  /**
@@ -528,6 +530,8 @@ export declare class Client implements LangSmithTracingClientInterface {
528
530
  get threads(): Threads;
529
531
  /** Access the traces resource (query, listRuns). */
530
532
  get traces(): Traces;
533
+ /** Access the public shared-run resource. */
534
+ get public(): Public;
531
535
  private processInputs;
532
536
  private processOutputs;
533
537
  private processMetadata;
@@ -580,7 +584,9 @@ export declare class Client implements LangSmithTracingClientInterface {
580
584
  private _sendBatchToOTELTranslator;
581
585
  private processRunOperation;
582
586
  protected _getServerInfo(): Promise<any>;
587
+ private _checkStainlessVersion;
583
588
  protected _ensureServerInfo(): Promise<Record<string, any>>;
589
+ _supportsSDBQuery(): Promise<boolean>;
584
590
  protected _getSettings(): Promise<LangSmithSettings>;
585
591
  /**
586
592
  * Flushes current queued traces.
@@ -1027,10 +1033,19 @@ export declare class Client implements LangSmithTracingClientInterface {
1027
1033
  _selectEvalResults(results: EvaluationResult | EvaluationResult[] | EvaluationResults): Array<EvaluationResult>;
1028
1034
  _logEvaluationFeedback(evaluatorResponse: EvaluationResult | EvaluationResult[] | EvaluationResults, run?: Run, sourceInfo?: {
1029
1035
  [key: string]: any;
1030
- }): Promise<[results: EvaluationResult[], feedbacks: Feedback[]]>;
1036
+ }, sessionId?: string): Promise<[results: EvaluationResult[], feedbacks: Feedback[]]>;
1037
+ logEvaluationFeedback(params: {
1038
+ evaluatorResponse: EvaluationResult | EvaluationResult[] | EvaluationResults;
1039
+ run: Run;
1040
+ projectId: string;
1041
+ sourceInfo?: {
1042
+ [key: string]: any;
1043
+ };
1044
+ }): Promise<EvaluationResult[]>;
1045
+ /** @deprecated Pass all params within an object and populate projectId. */
1031
1046
  logEvaluationFeedback(evaluatorResponse: EvaluationResult | EvaluationResult[] | EvaluationResults, run?: Run, sourceInfo?: {
1032
1047
  [key: string]: any;
1033
- }): Promise<EvaluationResult[]>;
1048
+ }, sessionId?: string): Promise<EvaluationResult[]>;
1034
1049
  /**
1035
1050
  * API for managing feedback configs
1036
1051
  */
package/dist/client.js CHANGED
@@ -609,6 +609,12 @@ export class Client {
609
609
  writable: true,
610
610
  value: void 0
611
611
  });
612
+ Object.defineProperty(this, "_stainlessVersionChecked", {
613
+ enumerable: true,
614
+ configurable: true,
615
+ writable: true,
616
+ value: false
617
+ });
612
618
  Object.defineProperty(this, "manualFlushMode", {
613
619
  enumerable: true,
614
620
  configurable: true,
@@ -936,27 +942,37 @@ export class Client {
936
942
  return needsV1Prefix ? `/v1/platform/${path}` : `/platform/${path}`;
937
943
  }
938
944
  get evaluators() {
945
+ this._checkStainlessVersion();
939
946
  return this.openAPIClient.onlineEvaluators;
940
947
  }
941
948
  get runs() {
949
+ this._checkStainlessVersion();
942
950
  return this.openAPIClient.runs;
943
951
  }
944
952
  /** Access the v2 sandboxes resource (registries, snapshots, boxes). */
945
953
  get sandboxes() {
954
+ this._checkStainlessVersion();
946
955
  return this.openAPIClient.sandboxes;
947
956
  }
948
957
  /** Access the v2 datasets resource (experimentRuns, etc.). */
949
958
  get datasets() {
959
+ this._checkStainlessVersion();
950
960
  return this.openAPIClient.datasets;
951
961
  }
952
962
  /** Access the threads resource (query, stats, listTraces). */
953
963
  get threads() {
964
+ this._checkStainlessVersion();
954
965
  return this.openAPIClient.threads;
955
966
  }
956
967
  /** Access the traces resource (query, listRuns). */
957
968
  get traces() {
969
+ this._checkStainlessVersion();
958
970
  return this.openAPIClient.traces;
959
971
  }
972
+ /** Access the public shared-run resource. */
973
+ get public() {
974
+ return this.openAPIClient.public;
975
+ }
960
976
  async processInputs(inputs) {
961
977
  if (this.hideInputs === false) {
962
978
  return inputs;
@@ -1443,15 +1459,26 @@ export class Client {
1443
1459
  }
1444
1460
  return json;
1445
1461
  }
1462
+ _checkStainlessVersion() {
1463
+ if (this._stainlessVersionChecked)
1464
+ return;
1465
+ this._stainlessVersionChecked = true;
1466
+ this._ensureServerInfo()
1467
+ .then((serverInfo) => {
1468
+ if (serverInfo?.version) {
1469
+ _checkBackendVersion(serverInfo.version);
1470
+ }
1471
+ })
1472
+ .catch(() => {
1473
+ // _ensureServerInfo handles and logs its own errors
1474
+ });
1475
+ }
1446
1476
  async _ensureServerInfo() {
1447
1477
  if (this._getServerInfoPromise === undefined) {
1448
1478
  this._getServerInfoPromise = (async () => {
1449
1479
  if (this._serverInfo === undefined) {
1450
1480
  try {
1451
1481
  this._serverInfo = await this._getServerInfo();
1452
- if (this._serverInfo?.version) {
1453
- _checkBackendVersion(this._serverInfo.version);
1454
- }
1455
1482
  }
1456
1483
  catch (e) {
1457
1484
  console.warn(`[LANGSMITH]: Failed to fetch info on supported operations. Falling back to batch operations and default limits. Info: ${e.status ?? "Unspecified status code"} ${e.message}`);
@@ -1467,6 +1494,10 @@ export class Client {
1467
1494
  return serverInfo;
1468
1495
  });
1469
1496
  }
1497
+ async _supportsSDBQuery() {
1498
+ const serverInfo = await this._ensureServerInfo();
1499
+ return serverInfo.instance_flags?.sdb_query_enabled === true;
1500
+ }
1470
1501
  async _getSettings() {
1471
1502
  if (!this.settings) {
1472
1503
  this.settings = this._get("/settings");
@@ -2405,6 +2436,9 @@ export class Client {
2405
2436
  ...(await Promise.all(projectNames.map((name) => this.readProject({ projectName: name }).then((project) => project.id)))),
2406
2437
  ];
2407
2438
  }
2439
+ if (projectIds_.length === 0) {
2440
+ throw new Error("At least one of projectNames or projectIds must be provided.");
2441
+ }
2408
2442
  const payload = {
2409
2443
  id,
2410
2444
  trace,
@@ -3788,7 +3822,7 @@ export class Client {
3788
3822
  }
3789
3823
  return results_;
3790
3824
  }
3791
- async _logEvaluationFeedback(evaluatorResponse, run, sourceInfo) {
3825
+ async _logEvaluationFeedback(evaluatorResponse, run, sourceInfo, sessionId) {
3792
3826
  const evalResults = this._selectEvalResults(evaluatorResponse);
3793
3827
  const feedbacks = [];
3794
3828
  for (const res of evalResults) {
@@ -3812,14 +3846,20 @@ export class Client {
3812
3846
  sourceRunId: res.sourceRunId,
3813
3847
  feedbackConfig: res.feedbackConfig,
3814
3848
  feedbackSourceType: "model",
3815
- sessionId: run?.session_id,
3849
+ sessionId: run?.session_id ?? sessionId,
3816
3850
  startTime: run?.start_time,
3817
3851
  }));
3818
3852
  }
3819
3853
  return [evalResults, feedbacks];
3820
3854
  }
3821
- async logEvaluationFeedback(evaluatorResponse, run, sourceInfo) {
3822
- const [results] = await this._logEvaluationFeedback(evaluatorResponse, run, sourceInfo);
3855
+ async logEvaluationFeedback(evaluatorResponseOrParams, run, sourceInfo, sessionId) {
3856
+ if (evaluatorResponseOrParams != null &&
3857
+ typeof evaluatorResponseOrParams === "object" &&
3858
+ "evaluatorResponse" in evaluatorResponseOrParams) {
3859
+ const [results] = await this._logEvaluationFeedback(evaluatorResponseOrParams.evaluatorResponse, evaluatorResponseOrParams.run, evaluatorResponseOrParams.sourceInfo, evaluatorResponseOrParams.projectId);
3860
+ return results;
3861
+ }
3862
+ const [results] = await this._logEvaluationFeedback(evaluatorResponseOrParams, run, sourceInfo, sessionId);
3823
3863
  return results;
3824
3864
  }
3825
3865
  /**
@@ -342,6 +342,8 @@ class _ExperimentManager {
342
342
  experiment: project,
343
343
  metadata: this._metadata,
344
344
  client: this.client,
345
+ runs: this._runs,
346
+ _runsArray: this._runsArray,
345
347
  evaluationResults: this._evaluationResults,
346
348
  summaryResults: this._summaryResults,
347
349
  numRepetitions: this._numRepetitions,
@@ -542,7 +544,11 @@ class _ExperimentManager {
542
544
  tracingEnabled: true,
543
545
  };
544
546
  const evaluatorResponse = await evaluator.evaluateRun(run, example, options);
545
- evaluationResults.results.push(...(await fields.client.logEvaluationFeedback(evaluatorResponse, run)));
547
+ evaluationResults.results.push(...(await fields.client.logEvaluationFeedback({
548
+ evaluatorResponse,
549
+ run,
550
+ projectId: this._getExperiment().id,
551
+ })));
546
552
  }
547
553
  catch (e) {
548
554
  console.error(`Error running evaluator ${evaluator.evaluateRun.name} on run ${run.id}: ${e}`);
@@ -1049,7 +1055,12 @@ async function _resolveExperiment(experiment, runs, client) {
1049
1055
  const firstRun = await runsCloneIterator
1050
1056
  .next()
1051
1057
  .then((result) => result.value);
1052
- const retrievedExperiment = await client.readProject(firstRun.sessionId);
1058
+ if (firstRun?.session_id == null) {
1059
+ throw new Error("Experiment ID not found for provided runs.");
1060
+ }
1061
+ const retrievedExperiment = await client.readProject({
1062
+ projectId: firstRun.session_id,
1063
+ });
1053
1064
  if (!retrievedExperiment.name) {
1054
1065
  throw new Error("Experiment name not found for provided runs.");
1055
1066
  }
@@ -334,6 +334,8 @@ export class _ExperimentManager {
334
334
  experiment: project,
335
335
  metadata: this._metadata,
336
336
  client: this.client,
337
+ runs: this._runs,
338
+ _runsArray: this._runsArray,
337
339
  evaluationResults: this._evaluationResults,
338
340
  summaryResults: this._summaryResults,
339
341
  numRepetitions: this._numRepetitions,
@@ -534,7 +536,11 @@ export class _ExperimentManager {
534
536
  tracingEnabled: true,
535
537
  };
536
538
  const evaluatorResponse = await evaluator.evaluateRun(run, example, options);
537
- evaluationResults.results.push(...(await fields.client.logEvaluationFeedback(evaluatorResponse, run)));
539
+ evaluationResults.results.push(...(await fields.client.logEvaluationFeedback({
540
+ evaluatorResponse,
541
+ run,
542
+ projectId: this._getExperiment().id,
543
+ })));
538
544
  }
539
545
  catch (e) {
540
546
  console.error(`Error running evaluator ${evaluator.evaluateRun.name} on run ${run.id}: ${e}`);
@@ -1040,7 +1046,12 @@ async function _resolveExperiment(experiment, runs, client) {
1040
1046
  const firstRun = await runsCloneIterator
1041
1047
  .next()
1042
1048
  .then((result) => result.value);
1043
- const retrievedExperiment = await client.readProject(firstRun.sessionId);
1049
+ if (firstRun?.session_id == null) {
1050
+ throw new Error("Experiment ID not found for provided runs.");
1051
+ }
1052
+ const retrievedExperiment = await client.readProject({
1053
+ projectId: firstRun.session_id,
1054
+ });
1044
1055
  if (!retrievedExperiment.name) {
1045
1056
  throw new Error("Experiment name not found for provided runs.");
1046
1057
  }
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadTracesForExperiment = loadTracesForExperiment;
6
7
  exports.evaluateComparative = evaluateComparative;
7
8
  const index_js_1 = require("../utils/uuid/src/index.cjs");
8
9
  const index_js_2 = require("../index.cjs");
@@ -10,6 +11,7 @@ const shuffle_js_1 = require("../utils/shuffle.cjs");
10
11
  const async_caller_js_1 = require("../utils/async_caller.cjs");
11
12
  const index_js_3 = __importDefault(require("../utils/p-retry/index.cjs"));
12
13
  const traceable_js_1 = require("../traceable.cjs");
14
+ const v2_migration_js_1 = require("../utils/v2_migration.cjs");
13
15
  function isExperimentResultsList(value) {
14
16
  return value.some((x) => typeof x !== "string");
15
17
  }
@@ -17,11 +19,15 @@ async function loadExperiment(client, experiment) {
17
19
  const value = typeof experiment === "string" ? experiment : experiment.experimentName;
18
20
  return client.readProject((0, index_js_1.validate)(value) ? { projectId: value } : { projectName: value });
19
21
  }
20
- async function loadTraces(client, experiment, options) {
21
- const executionOrder = options.loadNested ? undefined : 1;
22
- const runs = await client.listRuns((0, index_js_1.validate)(experiment)
23
- ? { projectId: experiment, executionOrder }
24
- : { projectName: experiment, executionOrder });
22
+ async function loadTracesForExperiment(client, project, options) {
23
+ // v1 `/runs/query` returns 501 on SmithDB-only backends; use v2 when it's available.
24
+ const isRoot = options.loadNested ? undefined : true;
25
+ const runs = (await client._supportsSDBQuery())
26
+ ? await (0, v2_migration_js_1.loadTracesV2)(client, project, { isRoot })
27
+ : await client.listRuns({
28
+ projectId: project.id,
29
+ executionOrder: options.loadNested ? undefined : 1,
30
+ });
25
31
  const treeMap = {};
26
32
  const runIdMap = {};
27
33
  const results = [];
@@ -121,7 +127,9 @@ async function evaluateComparative(experiments, options) {
121
127
  if (viewUrl != null) {
122
128
  console.log(`View results at: ${viewUrl}`);
123
129
  }
124
- const experimentRuns = await Promise.all(projects.map((p) => loadTraces(client, p.id, { loadNested: !!options.loadNested })));
130
+ const experimentRuns = await Promise.all(projects.map((project) => loadTracesForExperiment(client, project, {
131
+ loadNested: !!options.loadNested,
132
+ })));
125
133
  let exampleIdsIntersect;
126
134
  for (const runs of experimentRuns) {
127
135
  const exampleIdsSet = new Set(runs
@@ -1,7 +1,10 @@
1
1
  import { Client } from "../index.js";
2
- import { ComparativeExperiment, ComparisonEvaluationResult as ComparisonEvaluationResultRow, Example, Run } from "../schemas.js";
2
+ import { ComparativeExperiment, ComparisonEvaluationResult as ComparisonEvaluationResultRow, Example, Run, TracerSession } from "../schemas.js";
3
3
  import { evaluate } from "./index.js";
4
4
  type ExperimentResults = Awaited<ReturnType<typeof evaluate>>;
5
+ export declare function loadTracesForExperiment(client: Client, project: TracerSession, options: {
6
+ loadNested: boolean;
7
+ }): Promise<Run[]>;
5
8
  /** @deprecated Use ComparativeEvaluatorNew instead: (args: { runs, example, inputs, outputs, referenceOutputs }) => ... */
6
9
  export type _ComparativeEvaluatorLegacy = (runs: Run[], example: Example) => ComparisonEvaluationResultRow | Promise<ComparisonEvaluationResultRow>;
7
10
  export type _ComparativeEvaluator = (args: {
@@ -4,6 +4,7 @@ import { shuffle } from "../utils/shuffle.js";
4
4
  import { AsyncCaller } from "../utils/async_caller.js";
5
5
  import pRetry from "../utils/p-retry/index.js";
6
6
  import { getCurrentRunTree, traceable } from "../traceable.js";
7
+ import { loadTracesV2 } from "../utils/v2_migration.js";
7
8
  function isExperimentResultsList(value) {
8
9
  return value.some((x) => typeof x !== "string");
9
10
  }
@@ -11,11 +12,15 @@ async function loadExperiment(client, experiment) {
11
12
  const value = typeof experiment === "string" ? experiment : experiment.experimentName;
12
13
  return client.readProject(validate(value) ? { projectId: value } : { projectName: value });
13
14
  }
14
- async function loadTraces(client, experiment, options) {
15
- const executionOrder = options.loadNested ? undefined : 1;
16
- const runs = await client.listRuns(validate(experiment)
17
- ? { projectId: experiment, executionOrder }
18
- : { projectName: experiment, executionOrder });
15
+ export async function loadTracesForExperiment(client, project, options) {
16
+ // v1 `/runs/query` returns 501 on SmithDB-only backends; use v2 when it's available.
17
+ const isRoot = options.loadNested ? undefined : true;
18
+ const runs = (await client._supportsSDBQuery())
19
+ ? await loadTracesV2(client, project, { isRoot })
20
+ : await client.listRuns({
21
+ projectId: project.id,
22
+ executionOrder: options.loadNested ? undefined : 1,
23
+ });
19
24
  const treeMap = {};
20
25
  const runIdMap = {};
21
26
  const results = [];
@@ -115,7 +120,9 @@ export async function evaluateComparative(experiments, options) {
115
120
  if (viewUrl != null) {
116
121
  console.log(`View results at: ${viewUrl}`);
117
122
  }
118
- const experimentRuns = await Promise.all(projects.map((p) => loadTraces(client, p.id, { loadNested: !!options.loadNested })));
123
+ const experimentRuns = await Promise.all(projects.map((project) => loadTracesForExperiment(client, project, {
124
+ loadNested: !!options.loadNested,
125
+ })));
119
126
  let exampleIdsIntersect;
120
127
  for (const runs of experimentRuns) {
121
128
  const exampleIdsSet = new Set(runs
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LS_MESSAGE_VIEW_EXCLUDE = exports.__version__ = exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIUserAbortError = exports.APIError = exports.LangsmithError = exports.promptCacheSingleton = exports.configureGlobalPromptCache = exports.PromptCache = exports.Cache = exports.isTracingEnabled = exports.uuid7FromTime = exports.uuid7 = exports.getDefaultProjectName = exports.overrideFetchImplementation = exports.RunTree = exports.Client = void 0;
3
+ exports.LS_MESSAGE_VIEW_EXCLUDE = exports.__version__ = exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIUserAbortError = exports.APIError = exports.LangsmithError = exports.promptCacheSingleton = exports.configureGlobalPromptCache = exports.PromptCache = exports.Cache = exports.isTracingEnabled = exports.uuid7FromTime = exports.uuid7 = exports.computeRunIdForSecondaryReplica = exports.getDefaultProjectName = exports.overrideFetchImplementation = exports.RunTree = exports.Client = void 0;
4
4
  var client_js_1 = require("./client.cjs");
5
5
  Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_js_1.Client; } });
6
6
  var run_trees_js_1 = require("./run_trees.cjs");
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true
10
10
  var project_js_1 = require("./utils/project.cjs");
11
11
  Object.defineProperty(exports, "getDefaultProjectName", { enumerable: true, get: function () { return project_js_1.getDefaultProjectName; } });
12
12
  var uuid_js_1 = require("./uuid.cjs");
13
+ Object.defineProperty(exports, "computeRunIdForSecondaryReplica", { enumerable: true, get: function () { return uuid_js_1.computeRunIdForSecondaryReplica; } });
13
14
  Object.defineProperty(exports, "uuid7", { enumerable: true, get: function () { return uuid_js_1.uuid7; } });
14
15
  Object.defineProperty(exports, "uuid7FromTime", { enumerable: true, get: function () { return uuid_js_1.uuid7FromTime; } });
15
16
  var guard_js_1 = require("./utils/guard.cjs");
@@ -34,6 +35,6 @@ Object.defineProperty(exports, "UnprocessableEntityError", { enumerable: true, g
34
35
  Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return error_js_1.RateLimitError; } });
35
36
  Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return error_js_1.InternalServerError; } });
36
37
  // Update using pnpm bump-version
37
- exports.__version__ = "0.8.4";
38
+ exports.__version__ = "0.8.5";
38
39
  // Metadata key to hide a traced run from LangSmith's Messages View.
39
40
  exports.LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  export { Client, type ClientConfig, type LangSmithTracingClientInterface, } from "./client.js";
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, FeedbackConfigSchema, RetrieverOutput, } from "./schemas.js";
3
- export { RunTree, type RunTreeConfig } from "./run_trees.js";
3
+ export { RunTree, type RunTreeConfig, type WriteReplica } from "./run_trees.js";
4
4
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
- export { uuid7, uuid7FromTime } from "./uuid.js";
6
+ export { computeRunIdForSecondaryReplica, uuid7, uuid7FromTime, } from "./uuid.js";
7
7
  export { isTracingEnabled } from "./utils/guard.js";
8
8
  export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
9
9
  export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
10
- export declare const __version__ = "0.8.4";
10
+ export declare const __version__ = "0.8.5";
11
11
  export declare const LS_MESSAGE_VIEW_EXCLUDE: "ls_message_view_exclude";
package/dist/index.js CHANGED
@@ -2,11 +2,11 @@ export { Client, } from "./client.js";
2
2
  export { RunTree } from "./run_trees.js";
3
3
  export { overrideFetchImplementation } from "./singletons/fetch.js";
4
4
  export { getDefaultProjectName } from "./utils/project.js";
5
- export { uuid7, uuid7FromTime } from "./uuid.js";
5
+ export { computeRunIdForSecondaryReplica, uuid7, uuid7FromTime, } from "./uuid.js";
6
6
  export { isTracingEnabled } from "./utils/guard.js";
7
7
  export { Cache, PromptCache, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
8
8
  export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
9
9
  // Update using pnpm bump-version
10
- export const __version__ = "0.8.4";
10
+ export const __version__ = "0.8.5";
11
11
  // Metadata key to hide a traced run from LangSmith's Messages View.
12
12
  export const LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
@@ -46,12 +46,16 @@ function convertToDottedOrderFormat(epoch, runId, executionOrder = 1) {
46
46
  }
47
47
  const HEADER_SAFE_REPLICA_FIELDS = new Set([
48
48
  "projectName",
49
+ "primary",
49
50
  "updates",
50
51
  "reroot",
51
52
  ]);
52
53
  function filterReplicaForHeaders(replica) {
53
54
  const filtered = {};
54
55
  for (const key of Object.keys(replica)) {
56
+ if (key === "primary" && typeof replica[key] !== "boolean") {
57
+ continue;
58
+ }
55
59
  if (HEADER_SAFE_REPLICA_FIELDS.has(key)) {
56
60
  filtered[key] = replica[key];
57
61
  }
@@ -567,10 +571,10 @@ class RunTree {
567
571
  }
568
572
  }
569
573
  _remapForProject(params) {
570
- const { projectName, runtimeEnv, excludeChildRuns = true, reroot = false, distributedParentId, apiUrl, apiKey, workspaceId, } = params;
574
+ const { projectName, primary, runtimeEnv, excludeChildRuns = true, reroot = false, distributedParentId, apiUrl, apiKey, workspaceId, } = params;
571
575
  const baseRun = this._convertToCreate(this, runtimeEnv, excludeChildRuns);
572
- // Skip remapping if project name is the same
573
- if (projectName === this.project_name) {
576
+ // Preserve legacy behavior when `primary` is omitted.
577
+ if (primary === undefined && projectName === this.project_name) {
574
578
  return {
575
579
  ...baseRun,
576
580
  session_name: projectName,
@@ -643,6 +647,12 @@ class RunTree {
643
647
  }
644
648
  }
645
649
  }
650
+ if (primary) {
651
+ return {
652
+ ...baseRun,
653
+ session_name: projectName,
654
+ };
655
+ }
646
656
  // Remap IDs for the replica using nonCryptographicUuid7Deterministic
647
657
  // This ensures consistency across runs in the same replica while
648
658
  // preserving UUID7 properties (time-ordering, monotonicity)
@@ -691,9 +701,10 @@ class RunTree {
691
701
  try {
692
702
  const runtimeEnv = (0, env_js_2.getRuntimeEnvironment)();
693
703
  if (this.replicas && this.replicas.length > 0) {
694
- for (const { projectName, apiKey, apiUrl, workspaceId, reroot, client: replicaClient, } of this.replicas) {
704
+ for (const { projectName, primary, apiKey, apiUrl, workspaceId, reroot, client: replicaClient, } of this.replicas) {
695
705
  const runCreate = this._remapForProject({
696
706
  projectName: projectName ?? this.project_name,
707
+ primary,
697
708
  runtimeEnv,
698
709
  excludeChildRuns: true,
699
710
  reroot,
@@ -728,9 +739,10 @@ class RunTree {
728
739
  }
729
740
  async patchRun(options) {
730
741
  if (this.replicas && this.replicas.length > 0) {
731
- for (const { projectName, apiKey, apiUrl, workspaceId, updates, reroot, client: replicaClient, } of this.replicas) {
742
+ for (const { projectName, primary, apiKey, apiUrl, workspaceId, updates, reroot, client: replicaClient, } of this.replicas) {
732
743
  const runData = this._remapForProject({
733
744
  projectName: projectName ?? this.project_name,
745
+ primary,
734
746
  runtimeEnv: undefined,
735
747
  excludeChildRuns: true,
736
748
  reroot,
@@ -996,10 +1008,16 @@ function _getWriteReplicasFromEnv() {
996
1008
  `expected string, got ${typeof item.project_name}`);
997
1009
  continue;
998
1010
  }
1011
+ if (item.primary !== undefined && typeof item.primary !== "boolean") {
1012
+ console.warn(`Invalid primary type in LANGSMITH_RUNS_ENDPOINTS: ` +
1013
+ `expected boolean, got ${typeof item.primary}`);
1014
+ continue;
1015
+ }
999
1016
  replicas.push({
1000
1017
  apiUrl: item.api_url.replace(/\/$/, ""),
1001
1018
  apiKey: item.api_key,
1002
1019
  projectName: item.project_name ?? undefined,
1020
+ primary: item.primary ?? undefined,
1003
1021
  });
1004
1022
  }
1005
1023
  return replicas;
@@ -1039,9 +1057,8 @@ function _getWriteReplicasFromEnv() {
1039
1057
  }
1040
1058
  }
1041
1059
  function _ensureWriteReplicas(replicas) {
1042
- // If null -> fetch from env
1043
- if (replicas) {
1044
- return replicas.map((replica) => {
1060
+ const ensured = replicas
1061
+ ? replicas.map((replica) => {
1045
1062
  if (Array.isArray(replica)) {
1046
1063
  return {
1047
1064
  projectName: replica[0],
@@ -1049,9 +1066,12 @@ function _ensureWriteReplicas(replicas) {
1049
1066
  };
1050
1067
  }
1051
1068
  return replica;
1052
- });
1069
+ })
1070
+ : _getWriteReplicasFromEnv();
1071
+ if (ensured.filter((replica) => replica.primary === true).length > 1) {
1072
+ throw new Error("Only one replica can be marked as primary.");
1053
1073
  }
1054
- return _getWriteReplicasFromEnv();
1074
+ return ensured;
1055
1075
  }
1056
1076
  function _checkEndpointEnvUnset(parsed) {
1057
1077
  if (Object.keys(parsed).length > 0 &&
@@ -55,11 +55,13 @@ interface HeadersLike {
55
55
  set(name: string, value: string): void;
56
56
  }
57
57
  type ProjectReplica = [string, KVMap | undefined];
58
- type WriteReplica = {
58
+ export type WriteReplica = {
59
59
  apiUrl?: string;
60
60
  apiKey?: string;
61
61
  workspaceId?: string;
62
62
  projectName?: string;
63
+ /** Whether this replica keeps the original run IDs. */
64
+ primary?: boolean;
63
65
  updates?: KVMap | undefined;
64
66
  fromEnv?: boolean;
65
67
  reroot?: boolean;
package/dist/run_trees.js CHANGED
@@ -40,12 +40,16 @@ export function convertToDottedOrderFormat(epoch, runId, executionOrder = 1) {
40
40
  }
41
41
  const HEADER_SAFE_REPLICA_FIELDS = new Set([
42
42
  "projectName",
43
+ "primary",
43
44
  "updates",
44
45
  "reroot",
45
46
  ]);
46
47
  function filterReplicaForHeaders(replica) {
47
48
  const filtered = {};
48
49
  for (const key of Object.keys(replica)) {
50
+ if (key === "primary" && typeof replica[key] !== "boolean") {
51
+ continue;
52
+ }
49
53
  if (HEADER_SAFE_REPLICA_FIELDS.has(key)) {
50
54
  filtered[key] = replica[key];
51
55
  }
@@ -561,10 +565,10 @@ export class RunTree {
561
565
  }
562
566
  }
563
567
  _remapForProject(params) {
564
- const { projectName, runtimeEnv, excludeChildRuns = true, reroot = false, distributedParentId, apiUrl, apiKey, workspaceId, } = params;
568
+ const { projectName, primary, runtimeEnv, excludeChildRuns = true, reroot = false, distributedParentId, apiUrl, apiKey, workspaceId, } = params;
565
569
  const baseRun = this._convertToCreate(this, runtimeEnv, excludeChildRuns);
566
- // Skip remapping if project name is the same
567
- if (projectName === this.project_name) {
570
+ // Preserve legacy behavior when `primary` is omitted.
571
+ if (primary === undefined && projectName === this.project_name) {
568
572
  return {
569
573
  ...baseRun,
570
574
  session_name: projectName,
@@ -637,6 +641,12 @@ export class RunTree {
637
641
  }
638
642
  }
639
643
  }
644
+ if (primary) {
645
+ return {
646
+ ...baseRun,
647
+ session_name: projectName,
648
+ };
649
+ }
640
650
  // Remap IDs for the replica using nonCryptographicUuid7Deterministic
641
651
  // This ensures consistency across runs in the same replica while
642
652
  // preserving UUID7 properties (time-ordering, monotonicity)
@@ -685,9 +695,10 @@ export class RunTree {
685
695
  try {
686
696
  const runtimeEnv = getRuntimeEnvironment();
687
697
  if (this.replicas && this.replicas.length > 0) {
688
- for (const { projectName, apiKey, apiUrl, workspaceId, reroot, client: replicaClient, } of this.replicas) {
698
+ for (const { projectName, primary, apiKey, apiUrl, workspaceId, reroot, client: replicaClient, } of this.replicas) {
689
699
  const runCreate = this._remapForProject({
690
700
  projectName: projectName ?? this.project_name,
701
+ primary,
691
702
  runtimeEnv,
692
703
  excludeChildRuns: true,
693
704
  reroot,
@@ -722,9 +733,10 @@ export class RunTree {
722
733
  }
723
734
  async patchRun(options) {
724
735
  if (this.replicas && this.replicas.length > 0) {
725
- for (const { projectName, apiKey, apiUrl, workspaceId, updates, reroot, client: replicaClient, } of this.replicas) {
736
+ for (const { projectName, primary, apiKey, apiUrl, workspaceId, updates, reroot, client: replicaClient, } of this.replicas) {
726
737
  const runData = this._remapForProject({
727
738
  projectName: projectName ?? this.project_name,
739
+ primary,
728
740
  runtimeEnv: undefined,
729
741
  excludeChildRuns: true,
730
742
  reroot,
@@ -989,10 +1001,16 @@ function _getWriteReplicasFromEnv() {
989
1001
  `expected string, got ${typeof item.project_name}`);
990
1002
  continue;
991
1003
  }
1004
+ if (item.primary !== undefined && typeof item.primary !== "boolean") {
1005
+ console.warn(`Invalid primary type in LANGSMITH_RUNS_ENDPOINTS: ` +
1006
+ `expected boolean, got ${typeof item.primary}`);
1007
+ continue;
1008
+ }
992
1009
  replicas.push({
993
1010
  apiUrl: item.api_url.replace(/\/$/, ""),
994
1011
  apiKey: item.api_key,
995
1012
  projectName: item.project_name ?? undefined,
1013
+ primary: item.primary ?? undefined,
996
1014
  });
997
1015
  }
998
1016
  return replicas;
@@ -1032,9 +1050,8 @@ function _getWriteReplicasFromEnv() {
1032
1050
  }
1033
1051
  }
1034
1052
  function _ensureWriteReplicas(replicas) {
1035
- // If null -> fetch from env
1036
- if (replicas) {
1037
- return replicas.map((replica) => {
1053
+ const ensured = replicas
1054
+ ? replicas.map((replica) => {
1038
1055
  if (Array.isArray(replica)) {
1039
1056
  return {
1040
1057
  projectName: replica[0],
@@ -1042,9 +1059,12 @@ function _ensureWriteReplicas(replicas) {
1042
1059
  };
1043
1060
  }
1044
1061
  return replica;
1045
- });
1062
+ })
1063
+ : _getWriteReplicasFromEnv();
1064
+ if (ensured.filter((replica) => replica.primary === true).length > 1) {
1065
+ throw new Error("Only one replica can be marked as primary.");
1046
1066
  }
1047
- return _getWriteReplicasFromEnv();
1067
+ return ensured;
1048
1068
  }
1049
1069
  function _checkEndpointEnvUnset(parsed) {
1050
1070
  if (Object.keys(parsed).length > 0 &&
@@ -30,10 +30,18 @@ function _logTestFeedback(params) {
30
30
  throw new Error("Could not log feedback to LangSmith: missing run information. Please contact us for help.");
31
31
  }
32
32
  exports.evaluatorLogFeedbackPromises.add((async () => {
33
+ if (context.project == null) {
34
+ throw new Error("Could not log feedback to LangSmith: missing project information. Please contact us for help.");
35
+ }
33
36
  await exports.syncExamplePromises.get(exampleId);
34
- await client?.logEvaluationFeedback(feedback, runTree, sourceRunId !== undefined
35
- ? { __run: { run_id: sourceRunId } }
36
- : undefined);
37
+ await client?.logEvaluationFeedback({
38
+ evaluatorResponse: feedback,
39
+ run: runTree,
40
+ projectId: context.project.id,
41
+ sourceInfo: sourceRunId !== undefined
42
+ ? { __run: { run_id: sourceRunId } }
43
+ : undefined,
44
+ });
37
45
  })());
38
46
  }
39
47
  context.onFeedbackLogged?.(feedback);
@@ -25,10 +25,18 @@ export function _logTestFeedback(params) {
25
25
  throw new Error("Could not log feedback to LangSmith: missing run information. Please contact us for help.");
26
26
  }
27
27
  evaluatorLogFeedbackPromises.add((async () => {
28
+ if (context.project == null) {
29
+ throw new Error("Could not log feedback to LangSmith: missing project information. Please contact us for help.");
30
+ }
28
31
  await syncExamplePromises.get(exampleId);
29
- await client?.logEvaluationFeedback(feedback, runTree, sourceRunId !== undefined
30
- ? { __run: { run_id: sourceRunId } }
31
- : undefined);
32
+ await client?.logEvaluationFeedback({
33
+ evaluatorResponse: feedback,
34
+ run: runTree,
35
+ projectId: context.project.id,
36
+ sourceInfo: sourceRunId !== undefined
37
+ ? { __run: { run_id: sourceRunId } }
38
+ : undefined,
39
+ });
32
40
  })());
33
41
  }
34
42
  context.onFeedbackLogged?.(feedback);
@@ -573,6 +573,9 @@ function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
573
573
  const tracedFunction = (0, traceable_js_1.traceable)(async () => {
574
574
  return globals_js_1.testWrapperAsyncLocalStorageInstance.run({
575
575
  ...context,
576
+ dataset,
577
+ project,
578
+ client,
576
579
  currentExample: {
577
580
  inputs,
578
581
  outputs: referenceOutputs,
@@ -526,6 +526,9 @@ export function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
526
526
  const tracedFunction = traceable(async () => {
527
527
  return testWrapperAsyncLocalStorageInstance.run({
528
528
  ...context,
529
+ dataset,
530
+ project,
531
+ client,
529
532
  currentExample: {
530
533
  inputs,
531
534
  outputs: referenceOutputs,
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.v2RunToRun = v2RunToRun;
4
+ exports.loadTracesV2 = loadTracesV2;
5
+ // Omitting selects from `/v2/runs/query` returns only the run ID.
6
+ const V2_RUN_SELECTS = [
7
+ "ID",
8
+ "NAME",
9
+ "RUN_TYPE",
10
+ "STATUS",
11
+ "START_TIME",
12
+ "END_TIME",
13
+ "INPUTS",
14
+ "OUTPUTS",
15
+ "PARENT_RUN_IDS",
16
+ "PROJECT_ID",
17
+ "TRACE_ID",
18
+ "DOTTED_ORDER",
19
+ "REFERENCE_EXAMPLE_ID",
20
+ "ERROR",
21
+ ];
22
+ function v2RunToRun(run) {
23
+ if (run.id == null || run.name == null || run.run_type == null) {
24
+ throw new Error("V2 run response is missing required fields.");
25
+ }
26
+ return {
27
+ id: run.id,
28
+ name: run.name,
29
+ run_type: run.run_type.toLowerCase(),
30
+ start_time: run.start_time,
31
+ end_time: run.end_time,
32
+ trace_id: run.trace_id,
33
+ session_id: run.project_id,
34
+ parent_run_id: run.parent_run_ids?.at(-1),
35
+ dotted_order: run.dotted_order,
36
+ reference_example_id: run.reference_example_id,
37
+ inputs: run.inputs ?? {},
38
+ outputs: run.outputs,
39
+ error: run.error ?? undefined,
40
+ status: run.status?.toLowerCase(),
41
+ };
42
+ }
43
+ async function loadTracesV2(client, project, options) {
44
+ const runs = [];
45
+ const pager = client.runs.queryV2({
46
+ project_ids: [project.id],
47
+ min_start_time: new Date(project.start_time).toISOString(),
48
+ max_start_time: new Date(project.end_time ?? Date.now()).toISOString(),
49
+ is_root: options.isRoot,
50
+ selects: V2_RUN_SELECTS,
51
+ });
52
+ for await (const run of pager) {
53
+ runs.push(v2RunToRun(run));
54
+ }
55
+ return runs;
56
+ }
@@ -0,0 +1,7 @@
1
+ import type { Run as V2Run } from "../_openapi_client/resources/runs/runs.js";
2
+ import type { Client } from "../client.js";
3
+ import type { Run, TracerSession } from "../schemas.js";
4
+ export declare function v2RunToRun(run: V2Run): Run;
5
+ export declare function loadTracesV2(client: Client, project: TracerSession, options: {
6
+ isRoot?: boolean;
7
+ }): Promise<Run[]>;
@@ -0,0 +1,52 @@
1
+ // Omitting selects from `/v2/runs/query` returns only the run ID.
2
+ const V2_RUN_SELECTS = [
3
+ "ID",
4
+ "NAME",
5
+ "RUN_TYPE",
6
+ "STATUS",
7
+ "START_TIME",
8
+ "END_TIME",
9
+ "INPUTS",
10
+ "OUTPUTS",
11
+ "PARENT_RUN_IDS",
12
+ "PROJECT_ID",
13
+ "TRACE_ID",
14
+ "DOTTED_ORDER",
15
+ "REFERENCE_EXAMPLE_ID",
16
+ "ERROR",
17
+ ];
18
+ export function v2RunToRun(run) {
19
+ if (run.id == null || run.name == null || run.run_type == null) {
20
+ throw new Error("V2 run response is missing required fields.");
21
+ }
22
+ return {
23
+ id: run.id,
24
+ name: run.name,
25
+ run_type: run.run_type.toLowerCase(),
26
+ start_time: run.start_time,
27
+ end_time: run.end_time,
28
+ trace_id: run.trace_id,
29
+ session_id: run.project_id,
30
+ parent_run_id: run.parent_run_ids?.at(-1),
31
+ dotted_order: run.dotted_order,
32
+ reference_example_id: run.reference_example_id,
33
+ inputs: run.inputs ?? {},
34
+ outputs: run.outputs,
35
+ error: run.error ?? undefined,
36
+ status: run.status?.toLowerCase(),
37
+ };
38
+ }
39
+ export async function loadTracesV2(client, project, options) {
40
+ const runs = [];
41
+ const pager = client.runs.queryV2({
42
+ project_ids: [project.id],
43
+ min_start_time: new Date(project.start_time).toISOString(),
44
+ max_start_time: new Date(project.end_time ?? Date.now()).toISOString(),
45
+ is_root: options.isRoot,
46
+ selects: V2_RUN_SELECTS,
47
+ });
48
+ for await (const run of pager) {
49
+ runs.push(v2RunToRun(run));
50
+ }
51
+ return runs;
52
+ }
package/dist/uuid.cjs CHANGED
@@ -2,12 +2,32 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.uuid7FromTime = void 0;
4
4
  exports.uuid7 = uuid7;
5
+ exports.computeRunIdForSecondaryReplica = computeRunIdForSecondaryReplica;
5
6
  const index_js_1 = require("./utils/uuid/src/index.cjs");
6
- var _uuid_js_1 = require("./utils/_uuid.cjs");
7
- Object.defineProperty(exports, "uuid7FromTime", { enumerable: true, get: function () { return _uuid_js_1.uuid7FromTime; } });
7
+ const _uuid_js_1 = require("./utils/_uuid.cjs");
8
+ var _uuid_js_2 = require("./utils/_uuid.cjs");
9
+ Object.defineProperty(exports, "uuid7FromTime", { enumerable: true, get: function () { return _uuid_js_2.uuid7FromTime; } });
8
10
  /**
9
11
  * Generate a random UUID v7 string.
10
12
  */
11
13
  function uuid7() {
12
14
  return (0, index_js_1.v7)();
13
15
  }
16
+ /**
17
+ * Compute the run ID used for a secondary tracing replica.
18
+ *
19
+ * @param runId - The original UUID v7 run ID.
20
+ * @param projectName - The secondary replica's destination project name.
21
+ * @returns The run ID used in the secondary replica destination.
22
+ */
23
+ function computeRunIdForSecondaryReplica(runId, projectName) {
24
+ if (typeof projectName !== "string" || projectName.length === 0) {
25
+ throw new Error("projectName must be a non-empty string");
26
+ }
27
+ (0, _uuid_js_1.assertUuid)(runId, "runId");
28
+ const normalizedRunId = runId.toLowerCase();
29
+ if ((0, _uuid_js_1.getUuidVersion)(normalizedRunId) !== 7) {
30
+ throw new Error("runId must be a UUID v7");
31
+ }
32
+ return (0, _uuid_js_1.nonCryptographicUuid7Deterministic)(normalizedRunId, projectName);
33
+ }
package/dist/uuid.d.ts CHANGED
@@ -3,3 +3,11 @@ export { uuid7FromTime } from "./utils/_uuid.js";
3
3
  * Generate a random UUID v7 string.
4
4
  */
5
5
  export declare function uuid7(): string;
6
+ /**
7
+ * Compute the run ID used for a secondary tracing replica.
8
+ *
9
+ * @param runId - The original UUID v7 run ID.
10
+ * @param projectName - The secondary replica's destination project name.
11
+ * @returns The run ID used in the secondary replica destination.
12
+ */
13
+ export declare function computeRunIdForSecondaryReplica(runId: string, projectName: string): string;
package/dist/uuid.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { v7 as uuidv7 } from "./utils/uuid/src/index.js";
2
+ import { assertUuid, getUuidVersion, nonCryptographicUuid7Deterministic, } from "./utils/_uuid.js";
2
3
  export { uuid7FromTime } from "./utils/_uuid.js";
3
4
  /**
4
5
  * Generate a random UUID v7 string.
@@ -6,3 +7,21 @@ export { uuid7FromTime } from "./utils/_uuid.js";
6
7
  export function uuid7() {
7
8
  return uuidv7();
8
9
  }
10
+ /**
11
+ * Compute the run ID used for a secondary tracing replica.
12
+ *
13
+ * @param runId - The original UUID v7 run ID.
14
+ * @param projectName - The secondary replica's destination project name.
15
+ * @returns The run ID used in the secondary replica destination.
16
+ */
17
+ export function computeRunIdForSecondaryReplica(runId, projectName) {
18
+ if (typeof projectName !== "string" || projectName.length === 0) {
19
+ throw new Error("projectName must be a non-empty string");
20
+ }
21
+ assertUuid(runId, "runId");
22
+ const normalizedRunId = runId.toLowerCase();
23
+ if (getUuidVersion(normalizedRunId) !== 7) {
24
+ throw new Error("runId must be a UUID v7");
25
+ }
26
+ return nonCryptographicUuid7Deterministic(normalizedRunId, projectName);
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "pnpm@10.33.0",
6
6
  "files": [