langsmith 0.3.50 → 0.3.52

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
@@ -588,11 +588,11 @@ class Client {
588
588
  if (patch) {
589
589
  const sampled = [];
590
590
  for (const run of runs) {
591
- if (!this.filteredPostUuids.has(run.id)) {
591
+ if (!this.filteredPostUuids.has(run.trace_id)) {
592
592
  sampled.push(run);
593
593
  }
594
- else {
595
- this.filteredPostUuids.delete(run.id);
594
+ else if (run.id === run.trace_id) {
595
+ this.filteredPostUuids.delete(run.trace_id);
596
596
  }
597
597
  }
598
598
  return sampled;
package/dist/client.js CHANGED
@@ -550,11 +550,11 @@ export class Client {
550
550
  if (patch) {
551
551
  const sampled = [];
552
552
  for (const run of runs) {
553
- if (!this.filteredPostUuids.has(run.id)) {
553
+ if (!this.filteredPostUuids.has(run.trace_id)) {
554
554
  sampled.push(run);
555
555
  }
556
- else {
557
- this.filteredPostUuids.delete(run.id);
556
+ else if (run.id === run.trace_id) {
557
+ this.filteredPostUuids.delete(run.trace_id);
558
558
  }
559
559
  }
560
560
  return sampled;
package/dist/index.cjs CHANGED
@@ -10,4 +10,4 @@ Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true
10
10
  var project_js_1 = require("./utils/project.cjs");
11
11
  Object.defineProperty(exports, "getDefaultProjectName", { enumerable: true, get: function () { return project_js_1.getDefaultProjectName; } });
12
12
  // Update using yarn bump-version
13
- exports.__version__ = "0.3.50";
13
+ exports.__version__ = "0.3.52";
package/dist/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export type { Dataset, Example, TracerSession, Run, Feedback, RetrieverOutput, }
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
4
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
- export declare const __version__ = "0.3.50";
6
+ export declare const __version__ = "0.3.52";
package/dist/index.js CHANGED
@@ -3,4 +3,4 @@ export { RunTree } from "./run_trees.js";
3
3
  export { overrideFetchImplementation } from "./singletons/fetch.js";
4
4
  export { getDefaultProjectName } from "./utils/project.js";
5
5
  // Update using yarn bump-version
6
- export const __version__ = "0.3.50";
6
+ export const __version__ = "0.3.52";
@@ -776,17 +776,62 @@ function _getWriteReplicasFromEnv() {
776
776
  return [];
777
777
  try {
778
778
  const parsed = JSON.parse(envVar);
779
- _checkEndpointEnvUnset(parsed);
780
- return Object.entries(parsed).map(([url, key]) => ({
781
- apiUrl: url.replace(/\/$/, ""),
782
- apiKey: key,
783
- }));
779
+ if (Array.isArray(parsed)) {
780
+ const replicas = [];
781
+ for (const item of parsed) {
782
+ if (typeof item !== "object" || item === null) {
783
+ console.warn(`Invalid item type in LANGSMITH_RUNS_ENDPOINTS: ` +
784
+ `expected object, got ${typeof item}`);
785
+ continue;
786
+ }
787
+ if (typeof item.api_url !== "string") {
788
+ console.warn(`Invalid api_url type in LANGSMITH_RUNS_ENDPOINTS: ` +
789
+ `expected string, got ${typeof item.api_url}`);
790
+ continue;
791
+ }
792
+ if (typeof item.api_key !== "string") {
793
+ console.warn(`Invalid api_key type in LANGSMITH_RUNS_ENDPOINTS: ` +
794
+ `expected string, got ${typeof item.api_key}`);
795
+ continue;
796
+ }
797
+ replicas.push({
798
+ apiUrl: item.api_url.replace(/\/$/, ""),
799
+ apiKey: item.api_key,
800
+ });
801
+ }
802
+ return replicas;
803
+ }
804
+ else if (typeof parsed === "object" && parsed !== null) {
805
+ _checkEndpointEnvUnset(parsed);
806
+ const replicas = [];
807
+ for (const [url, key] of Object.entries(parsed)) {
808
+ const cleanUrl = url.replace(/\/$/, "");
809
+ if (typeof key === "string") {
810
+ replicas.push({
811
+ apiUrl: cleanUrl,
812
+ apiKey: key,
813
+ });
814
+ }
815
+ else {
816
+ console.warn(`Invalid value type in LANGSMITH_RUNS_ENDPOINTS for URL ${url}: ` +
817
+ `expected string, got ${typeof key}`);
818
+ continue;
819
+ }
820
+ }
821
+ return replicas;
822
+ }
823
+ else {
824
+ console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON array of " +
825
+ `objects with api_url and api_key properties, or object mapping url->apiKey, got ${typeof parsed}`);
826
+ return [];
827
+ }
784
828
  }
785
829
  catch (e) {
786
830
  if ((0, error_js_1.isConflictingEndpointsError)(e)) {
787
831
  throw e;
788
832
  }
789
- console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON mapping of url->apiKey");
833
+ console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON array of " +
834
+ "objects with api_url and api_key properties, or object mapping url->apiKey");
790
835
  return [];
791
836
  }
792
837
  }
package/dist/run_trees.js CHANGED
@@ -735,17 +735,62 @@ function _getWriteReplicasFromEnv() {
735
735
  return [];
736
736
  try {
737
737
  const parsed = JSON.parse(envVar);
738
- _checkEndpointEnvUnset(parsed);
739
- return Object.entries(parsed).map(([url, key]) => ({
740
- apiUrl: url.replace(/\/$/, ""),
741
- apiKey: key,
742
- }));
738
+ if (Array.isArray(parsed)) {
739
+ const replicas = [];
740
+ for (const item of parsed) {
741
+ if (typeof item !== "object" || item === null) {
742
+ console.warn(`Invalid item type in LANGSMITH_RUNS_ENDPOINTS: ` +
743
+ `expected object, got ${typeof item}`);
744
+ continue;
745
+ }
746
+ if (typeof item.api_url !== "string") {
747
+ console.warn(`Invalid api_url type in LANGSMITH_RUNS_ENDPOINTS: ` +
748
+ `expected string, got ${typeof item.api_url}`);
749
+ continue;
750
+ }
751
+ if (typeof item.api_key !== "string") {
752
+ console.warn(`Invalid api_key type in LANGSMITH_RUNS_ENDPOINTS: ` +
753
+ `expected string, got ${typeof item.api_key}`);
754
+ continue;
755
+ }
756
+ replicas.push({
757
+ apiUrl: item.api_url.replace(/\/$/, ""),
758
+ apiKey: item.api_key,
759
+ });
760
+ }
761
+ return replicas;
762
+ }
763
+ else if (typeof parsed === "object" && parsed !== null) {
764
+ _checkEndpointEnvUnset(parsed);
765
+ const replicas = [];
766
+ for (const [url, key] of Object.entries(parsed)) {
767
+ const cleanUrl = url.replace(/\/$/, "");
768
+ if (typeof key === "string") {
769
+ replicas.push({
770
+ apiUrl: cleanUrl,
771
+ apiKey: key,
772
+ });
773
+ }
774
+ else {
775
+ console.warn(`Invalid value type in LANGSMITH_RUNS_ENDPOINTS for URL ${url}: ` +
776
+ `expected string, got ${typeof key}`);
777
+ continue;
778
+ }
779
+ }
780
+ return replicas;
781
+ }
782
+ else {
783
+ console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON array of " +
784
+ `objects with api_url and api_key properties, or object mapping url->apiKey, got ${typeof parsed}`);
785
+ return [];
786
+ }
743
787
  }
744
788
  catch (e) {
745
789
  if (isConflictingEndpointsError(e)) {
746
790
  throw e;
747
791
  }
748
- console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON mapping of url->apiKey");
792
+ console.warn("Invalid LANGSMITH_RUNS_ENDPOINTS – must be valid JSON array of " +
793
+ "objects with api_url and api_key properties, or object mapping url->apiKey");
749
794
  return [];
750
795
  }
751
796
  }
package/dist/vercel.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AISDKExporter = void 0;
3
+ exports.AISDKExporter = exports.toStrippedIsoTime = exports.parseStrippedIsoTime = void 0;
4
+ exports.getMutableRunCreate = getMutableRunCreate;
4
5
  const vercel_js_1 = require("./utils/vercel.cjs");
5
6
  const index_js_1 = require("./index.cjs");
6
7
  const uuid_1 = require("uuid");
@@ -172,20 +173,58 @@ function reparentDotOrder(dotOrder, sourceRunId, parentDotOrder) {
172
173
  return dotOrder;
173
174
  return joinDotOrder(...parentDotOrder.split("."), ...segments.slice(sourceIndex));
174
175
  }
176
+ // Helper function to convert stripped ISO string back to parseable format
177
+ const parseStrippedIsoTime = (stripped) => {
178
+ // Insert back the removed characters: YYYYMMDDTHHMMSSSSSSSS -> YYYY-MM-DDTHH:MM:SS.SSSZ
179
+ // The stripped format is timestamp part only (no Z - that becomes the separator)
180
+ // Format includes microseconds: 20231201T120000000000 (milliseconds + microseconds)
181
+ const year = stripped.slice(0, 4);
182
+ const month = stripped.slice(4, 6);
183
+ const day = stripped.slice(6, 8);
184
+ const hour = stripped.slice(9, 11); // Skip 'T'
185
+ const minute = stripped.slice(11, 13);
186
+ const second = stripped.slice(13, 15);
187
+ const ms = stripped.slice(15, 18); // Only use first 3 digits for milliseconds
188
+ // Ignore microseconds (18-21) as Date only has millisecond precision
189
+ return new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}Z`);
190
+ };
191
+ exports.parseStrippedIsoTime = parseStrippedIsoTime;
192
+ // Helper function to convert Date back to stripped format
193
+ const toStrippedIsoTime = (date) => {
194
+ return stripNonAlphanumeric(date.toISOString().slice(0, -1)) + "000";
195
+ };
196
+ exports.toStrippedIsoTime = toStrippedIsoTime;
175
197
  function getMutableRunCreate(dotOrder) {
176
198
  const segments = dotOrder.split(".").map((i) => {
177
199
  const [startTime, runId] = i.split("Z");
178
200
  return { startTime, runId };
179
201
  });
202
+ // Iteratively check and fix timing to ensure each segment is greater than its parent
203
+ for (let i = 1; i < segments.length; i++) {
204
+ const parentTime = (0, exports.parseStrippedIsoTime)(segments[i - 1].startTime);
205
+ const currentTime = (0, exports.parseStrippedIsoTime)(segments[i].startTime);
206
+ if (currentTime.getTime() <= parentTime.getTime()) {
207
+ // Increment by 1 millisecond to make it greater than parent
208
+ const newTime = new Date(parentTime.getTime() + 1);
209
+ segments[i].startTime = (0, exports.toStrippedIsoTime)(newTime);
210
+ }
211
+ }
212
+ // Reconstruct the dotted order with potentially updated timestamps
213
+ const updatedDotOrder = segments
214
+ .map((segment) => `${segment.startTime}Z${segment.runId}`)
215
+ .join(".");
180
216
  const traceId = segments[0].runId;
181
217
  const parentRunId = segments.at(-2)?.runId;
182
218
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
183
219
  const runId = segments.at(-1).runId;
220
+ // If this is the last segment (current run), set start_time to its ISO timestamp
221
+ const lastSegmentTime = (0, exports.parseStrippedIsoTime)(segments.at(-1).startTime);
184
222
  return {
185
223
  id: runId,
186
224
  trace_id: traceId,
187
- dotted_order: dotOrder,
225
+ dotted_order: updatedDotOrder,
188
226
  parent_run_id: parentRunId,
227
+ start_time: lastSegmentTime.toISOString(),
189
228
  };
190
229
  }
191
230
  function convertToTimestamp([seconds, nanoseconds]) {
@@ -777,10 +816,15 @@ class AISDKExporter {
777
816
  }
778
817
  this.seenSpanInfo[task.id].dotOrder = taskDotOrder;
779
818
  if (!this.seenSpanInfo[task.id].sent) {
780
- sampled.push({
819
+ const updated = {
781
820
  ...task.run,
782
821
  ...getMutableRunCreate(taskDotOrder),
783
- });
822
+ };
823
+ if (updated.end_time !== undefined &&
824
+ updated.end_time < updated.start_time) {
825
+ updated.end_time = new Date(new Date(updated.start_time).getTime() + 1).toISOString();
826
+ }
827
+ sampled.push(updated);
784
828
  }
785
829
  this.seenSpanInfo[task.id].sent = true;
786
830
  }
package/dist/vercel.d.ts CHANGED
@@ -7,6 +7,16 @@ export interface TelemetrySettings extends AITelemetrySettings {
7
7
  /** Name of the run sent to LangSmith */
8
8
  runName?: string;
9
9
  }
10
+ interface MutableRunCreate {
11
+ id: string;
12
+ trace_id: string;
13
+ dotted_order: string;
14
+ parent_run_id: string | undefined;
15
+ start_time: string;
16
+ }
17
+ export declare const parseStrippedIsoTime: (stripped: string) => Date;
18
+ export declare const toStrippedIsoTime: (date: Date) => string;
19
+ export declare function getMutableRunCreate(dotOrder: string): MutableRunCreate;
10
20
  /**
11
21
  * OpenTelemetry trace exporter for Vercel AI SDK.
12
22
  *
@@ -81,3 +91,4 @@ export declare class AISDKExporter {
81
91
  forceFlush(): Promise<void>;
82
92
  protected logDebug(...args: Parameters<typeof console.debug>): void;
83
93
  }
94
+ export {};
package/dist/vercel.js CHANGED
@@ -169,20 +169,56 @@ function reparentDotOrder(dotOrder, sourceRunId, parentDotOrder) {
169
169
  return dotOrder;
170
170
  return joinDotOrder(...parentDotOrder.split("."), ...segments.slice(sourceIndex));
171
171
  }
172
- function getMutableRunCreate(dotOrder) {
172
+ // Helper function to convert stripped ISO string back to parseable format
173
+ export const parseStrippedIsoTime = (stripped) => {
174
+ // Insert back the removed characters: YYYYMMDDTHHMMSSSSSSSS -> YYYY-MM-DDTHH:MM:SS.SSSZ
175
+ // The stripped format is timestamp part only (no Z - that becomes the separator)
176
+ // Format includes microseconds: 20231201T120000000000 (milliseconds + microseconds)
177
+ const year = stripped.slice(0, 4);
178
+ const month = stripped.slice(4, 6);
179
+ const day = stripped.slice(6, 8);
180
+ const hour = stripped.slice(9, 11); // Skip 'T'
181
+ const minute = stripped.slice(11, 13);
182
+ const second = stripped.slice(13, 15);
183
+ const ms = stripped.slice(15, 18); // Only use first 3 digits for milliseconds
184
+ // Ignore microseconds (18-21) as Date only has millisecond precision
185
+ return new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}Z`);
186
+ };
187
+ // Helper function to convert Date back to stripped format
188
+ export const toStrippedIsoTime = (date) => {
189
+ return stripNonAlphanumeric(date.toISOString().slice(0, -1)) + "000";
190
+ };
191
+ export function getMutableRunCreate(dotOrder) {
173
192
  const segments = dotOrder.split(".").map((i) => {
174
193
  const [startTime, runId] = i.split("Z");
175
194
  return { startTime, runId };
176
195
  });
196
+ // Iteratively check and fix timing to ensure each segment is greater than its parent
197
+ for (let i = 1; i < segments.length; i++) {
198
+ const parentTime = parseStrippedIsoTime(segments[i - 1].startTime);
199
+ const currentTime = parseStrippedIsoTime(segments[i].startTime);
200
+ if (currentTime.getTime() <= parentTime.getTime()) {
201
+ // Increment by 1 millisecond to make it greater than parent
202
+ const newTime = new Date(parentTime.getTime() + 1);
203
+ segments[i].startTime = toStrippedIsoTime(newTime);
204
+ }
205
+ }
206
+ // Reconstruct the dotted order with potentially updated timestamps
207
+ const updatedDotOrder = segments
208
+ .map((segment) => `${segment.startTime}Z${segment.runId}`)
209
+ .join(".");
177
210
  const traceId = segments[0].runId;
178
211
  const parentRunId = segments.at(-2)?.runId;
179
212
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
180
213
  const runId = segments.at(-1).runId;
214
+ // If this is the last segment (current run), set start_time to its ISO timestamp
215
+ const lastSegmentTime = parseStrippedIsoTime(segments.at(-1).startTime);
181
216
  return {
182
217
  id: runId,
183
218
  trace_id: traceId,
184
- dotted_order: dotOrder,
219
+ dotted_order: updatedDotOrder,
185
220
  parent_run_id: parentRunId,
221
+ start_time: lastSegmentTime.toISOString(),
186
222
  };
187
223
  }
188
224
  function convertToTimestamp([seconds, nanoseconds]) {
@@ -774,10 +810,15 @@ export class AISDKExporter {
774
810
  }
775
811
  this.seenSpanInfo[task.id].dotOrder = taskDotOrder;
776
812
  if (!this.seenSpanInfo[task.id].sent) {
777
- sampled.push({
813
+ const updated = {
778
814
  ...task.run,
779
815
  ...getMutableRunCreate(taskDotOrder),
780
- });
816
+ };
817
+ if (updated.end_time !== undefined &&
818
+ updated.end_time < updated.start_time) {
819
+ updated.end_time = new Date(new Date(updated.start_time).getTime() + 1).toISOString();
820
+ }
821
+ sampled.push(updated);
781
822
  }
782
823
  this.seenSpanInfo[task.id].sent = true;
783
824
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.50",
3
+ "version": "0.3.52",
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": [