langsmith 0.3.52 → 0.3.53

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.
@@ -6,24 +6,10 @@ const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
6
6
  const constants_js_1 = require("./constants.cjs");
7
7
  const utils_js_1 = require("./utils.cjs");
8
8
  const run_trees_js_1 = require("../../run_trees.cjs");
9
- const NANOSECOND_DIGITS = 9;
10
- const MICROSECOND_DIGITS = 6;
11
9
  function isTraceableSpan(span) {
12
10
  return (span.attributes[constants_js_1.LANGSMITH_TRACEABLE] === "true" ||
13
11
  typeof span.attributes["ai.operationId"] === "string");
14
12
  }
15
- /**
16
- * Convert hrTime to timestamp, for example "2019-05-14T17:00:00.000123Z"
17
- * @param time
18
- */
19
- function hrTimeToTimeStamp(time) {
20
- const precision = NANOSECOND_DIGITS;
21
- const tmp = `${"0".repeat(precision)}${time[1]}Z`;
22
- const nanoString = tmp.substring(tmp.length - precision - 1);
23
- const date = new Date(time[0] * 1000).toISOString();
24
- // We only need 6 digits of precision for the dotted order
25
- return `${date.replace("000Z", nanoString.slice(0, MICROSECOND_DIGITS))}Z`;
26
- }
27
13
  function getParentSpanId(span) {
28
14
  // Backcompat shim to support OTEL 1.x and 2.x
29
15
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -53,35 +39,20 @@ class LangSmithOTLPSpanProcessor extends sdk_trace_base_1.BatchSpanProcessor {
53
39
  this.traceMap[span.spanContext().traceId].spanCount++;
54
40
  const isTraceable = isTraceableSpan(span);
55
41
  const parentSpanId = getParentSpanId(span);
42
+ this.traceMap[span.spanContext().traceId].spanInfo[span.spanContext().spanId] = {
43
+ isTraceable,
44
+ parentSpanId,
45
+ };
56
46
  let currentCandidateParentSpanId = parentSpanId;
57
47
  let traceableParentId;
58
- let parentDottedOrder;
59
- // LangSmith uses the first span's id as the trace id, NOT the actual OTEL trace id
60
- // Default to the current span if no parent information is present
61
- let lsTraceId = (0, utils_js_1.getUuidFromOtelSpanId)(span.spanContext().spanId);
62
48
  while (currentCandidateParentSpanId) {
63
49
  const currentSpanInfo = this.traceMap[span.spanContext().traceId].spanInfo[currentCandidateParentSpanId];
64
50
  if (currentSpanInfo?.isTraceable) {
65
51
  traceableParentId = currentCandidateParentSpanId;
66
- parentDottedOrder = currentSpanInfo.dottedOrder;
67
- lsTraceId = currentSpanInfo.lsTraceId;
68
52
  break;
69
53
  }
70
54
  currentCandidateParentSpanId = currentSpanInfo?.parentSpanId;
71
55
  }
72
- const startTimestamp = hrTimeToTimeStamp(span.startTime);
73
- const spanUuid = (0, utils_js_1.getUuidFromOtelSpanId)(span.spanContext().spanId);
74
- const dottedOrderComponent = (0, run_trees_js_1.stripNonAlphanumeric)(startTimestamp) + spanUuid;
75
- const currentDottedOrder = parentDottedOrder
76
- ? `${parentDottedOrder}.${dottedOrderComponent}`
77
- : dottedOrderComponent;
78
- this.traceMap[span.spanContext().traceId].spanInfo[span.spanContext().spanId] = {
79
- isTraceable,
80
- lsTraceId,
81
- spanId: span.spanContext().spanId,
82
- parentSpanId,
83
- dottedOrder: currentDottedOrder,
84
- };
85
56
  if (!traceableParentId) {
86
57
  span.attributes[constants_js_1.LANGSMITH_IS_ROOT] = true;
87
58
  }
@@ -89,8 +60,6 @@ class LangSmithOTLPSpanProcessor extends sdk_trace_base_1.BatchSpanProcessor {
89
60
  span.attributes[constants_js_1.LANGSMITH_PARENT_RUN_ID] =
90
61
  (0, utils_js_1.getUuidFromOtelSpanId)(traceableParentId);
91
62
  }
92
- span.attributes[constants_js_1.LANGSMITH_DOTTED_ORDER] = currentDottedOrder;
93
- span.attributes[constants_js_1.LANGSMITH_TRACE_ID] = lsTraceId;
94
63
  if (isTraceable) {
95
64
  super.onStart(span, parentContext);
96
65
  }
@@ -1,25 +1,11 @@
1
1
  import { BatchSpanProcessor, } from "@opentelemetry/sdk-trace-base";
2
- import { LANGSMITH_IS_ROOT, LANGSMITH_PARENT_RUN_ID, LANGSMITH_TRACEABLE, LANGSMITH_DOTTED_ORDER, LANGSMITH_TRACE_ID, } from "./constants.js";
2
+ import { LANGSMITH_IS_ROOT, LANGSMITH_PARENT_RUN_ID, LANGSMITH_TRACEABLE, } from "./constants.js";
3
3
  import { getUuidFromOtelSpanId } from "./utils.js";
4
- import { RunTree, stripNonAlphanumeric } from "../../run_trees.js";
5
- const NANOSECOND_DIGITS = 9;
6
- const MICROSECOND_DIGITS = 6;
4
+ import { RunTree } from "../../run_trees.js";
7
5
  export function isTraceableSpan(span) {
8
6
  return (span.attributes[LANGSMITH_TRACEABLE] === "true" ||
9
7
  typeof span.attributes["ai.operationId"] === "string");
10
8
  }
11
- /**
12
- * Convert hrTime to timestamp, for example "2019-05-14T17:00:00.000123Z"
13
- * @param time
14
- */
15
- function hrTimeToTimeStamp(time) {
16
- const precision = NANOSECOND_DIGITS;
17
- const tmp = `${"0".repeat(precision)}${time[1]}Z`;
18
- const nanoString = tmp.substring(tmp.length - precision - 1);
19
- const date = new Date(time[0] * 1000).toISOString();
20
- // We only need 6 digits of precision for the dotted order
21
- return `${date.replace("000Z", nanoString.slice(0, MICROSECOND_DIGITS))}Z`;
22
- }
23
9
  function getParentSpanId(span) {
24
10
  // Backcompat shim to support OTEL 1.x and 2.x
25
11
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -49,35 +35,20 @@ export class LangSmithOTLPSpanProcessor extends BatchSpanProcessor {
49
35
  this.traceMap[span.spanContext().traceId].spanCount++;
50
36
  const isTraceable = isTraceableSpan(span);
51
37
  const parentSpanId = getParentSpanId(span);
38
+ this.traceMap[span.spanContext().traceId].spanInfo[span.spanContext().spanId] = {
39
+ isTraceable,
40
+ parentSpanId,
41
+ };
52
42
  let currentCandidateParentSpanId = parentSpanId;
53
43
  let traceableParentId;
54
- let parentDottedOrder;
55
- // LangSmith uses the first span's id as the trace id, NOT the actual OTEL trace id
56
- // Default to the current span if no parent information is present
57
- let lsTraceId = getUuidFromOtelSpanId(span.spanContext().spanId);
58
44
  while (currentCandidateParentSpanId) {
59
45
  const currentSpanInfo = this.traceMap[span.spanContext().traceId].spanInfo[currentCandidateParentSpanId];
60
46
  if (currentSpanInfo?.isTraceable) {
61
47
  traceableParentId = currentCandidateParentSpanId;
62
- parentDottedOrder = currentSpanInfo.dottedOrder;
63
- lsTraceId = currentSpanInfo.lsTraceId;
64
48
  break;
65
49
  }
66
50
  currentCandidateParentSpanId = currentSpanInfo?.parentSpanId;
67
51
  }
68
- const startTimestamp = hrTimeToTimeStamp(span.startTime);
69
- const spanUuid = getUuidFromOtelSpanId(span.spanContext().spanId);
70
- const dottedOrderComponent = stripNonAlphanumeric(startTimestamp) + spanUuid;
71
- const currentDottedOrder = parentDottedOrder
72
- ? `${parentDottedOrder}.${dottedOrderComponent}`
73
- : dottedOrderComponent;
74
- this.traceMap[span.spanContext().traceId].spanInfo[span.spanContext().spanId] = {
75
- isTraceable,
76
- lsTraceId,
77
- spanId: span.spanContext().spanId,
78
- parentSpanId,
79
- dottedOrder: currentDottedOrder,
80
- };
81
52
  if (!traceableParentId) {
82
53
  span.attributes[LANGSMITH_IS_ROOT] = true;
83
54
  }
@@ -85,8 +56,6 @@ export class LangSmithOTLPSpanProcessor extends BatchSpanProcessor {
85
56
  span.attributes[LANGSMITH_PARENT_RUN_ID] =
86
57
  getUuidFromOtelSpanId(traceableParentId);
87
58
  }
88
- span.attributes[LANGSMITH_DOTTED_ORDER] = currentDottedOrder;
89
- span.attributes[LANGSMITH_TRACE_ID] = lsTraceId;
90
59
  if (isTraceable) {
91
60
  super.onStart(span, parentContext);
92
61
  }
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.52";
13
+ exports.__version__ = "0.3.53";
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.52";
6
+ export declare const __version__ = "0.3.53";
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.52";
6
+ export const __version__ = "0.3.53";
@@ -34,7 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.RunTree = void 0;
37
- exports.stripNonAlphanumeric = stripNonAlphanumeric;
38
37
  exports.convertToDottedOrderFormat = convertToDottedOrderFormat;
39
38
  exports.isRunTree = isRunTree;
40
39
  exports.isRunnableConfigLike = isRunnableConfigLike;
@@ -1,6 +1,5 @@
1
1
  import { Client } from "./client.js";
2
2
  import { Attachments, BaseRun, KVMap, RunCreate } from "./schemas.js";
3
- export declare function stripNonAlphanumeric(input: string): string;
4
3
  export declare function convertToDottedOrderFormat(epoch: number, runId: string, executionOrder?: number): {
5
4
  dottedOrder: string;
6
5
  microsecondPrecisionDatestring: string;
package/dist/run_trees.js CHANGED
@@ -7,7 +7,7 @@ import { getEnvironmentVariable, getRuntimeEnvironment, } from "./utils/env.js";
7
7
  import { getDefaultProjectName } from "./utils/project.js";
8
8
  import { getLangSmithEnvironmentVariable } from "./utils/env.js";
9
9
  import { warnOnce } from "./utils/warn.js";
10
- export function stripNonAlphanumeric(input) {
10
+ function stripNonAlphanumeric(input) {
11
11
  return input.replace(/[-:.]/g, "");
12
12
  }
13
13
  export function convertToDottedOrderFormat(epoch, runId, executionOrder = 1) {
package/dist/vercel.cjs CHANGED
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AISDKExporter = exports.toStrippedIsoTime = exports.parseStrippedIsoTime = void 0;
4
- exports.getMutableRunCreate = getMutableRunCreate;
3
+ exports.AISDKExporter = void 0;
5
4
  const vercel_js_1 = require("./utils/vercel.cjs");
6
5
  const index_js_1 = require("./index.cjs");
7
6
  const uuid_1 = require("uuid");
@@ -173,58 +172,20 @@ function reparentDotOrder(dotOrder, sourceRunId, parentDotOrder) {
173
172
  return dotOrder;
174
173
  return joinDotOrder(...parentDotOrder.split("."), ...segments.slice(sourceIndex));
175
174
  }
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;
197
175
  function getMutableRunCreate(dotOrder) {
198
176
  const segments = dotOrder.split(".").map((i) => {
199
177
  const [startTime, runId] = i.split("Z");
200
178
  return { startTime, runId };
201
179
  });
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(".");
216
180
  const traceId = segments[0].runId;
217
181
  const parentRunId = segments.at(-2)?.runId;
218
182
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
219
183
  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);
222
184
  return {
223
185
  id: runId,
224
186
  trace_id: traceId,
225
- dotted_order: updatedDotOrder,
187
+ dotted_order: dotOrder,
226
188
  parent_run_id: parentRunId,
227
- start_time: lastSegmentTime.toISOString(),
228
189
  };
229
190
  }
230
191
  function convertToTimestamp([seconds, nanoseconds]) {
@@ -816,15 +777,10 @@ class AISDKExporter {
816
777
  }
817
778
  this.seenSpanInfo[task.id].dotOrder = taskDotOrder;
818
779
  if (!this.seenSpanInfo[task.id].sent) {
819
- const updated = {
780
+ sampled.push({
820
781
  ...task.run,
821
782
  ...getMutableRunCreate(taskDotOrder),
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);
783
+ });
828
784
  }
829
785
  this.seenSpanInfo[task.id].sent = true;
830
786
  }
package/dist/vercel.d.ts CHANGED
@@ -7,16 +7,6 @@ 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;
20
10
  /**
21
11
  * OpenTelemetry trace exporter for Vercel AI SDK.
22
12
  *
@@ -91,4 +81,3 @@ export declare class AISDKExporter {
91
81
  forceFlush(): Promise<void>;
92
82
  protected logDebug(...args: Parameters<typeof console.debug>): void;
93
83
  }
94
- export {};
package/dist/vercel.js CHANGED
@@ -169,56 +169,20 @@ function reparentDotOrder(dotOrder, sourceRunId, parentDotOrder) {
169
169
  return dotOrder;
170
170
  return joinDotOrder(...parentDotOrder.split("."), ...segments.slice(sourceIndex));
171
171
  }
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) {
172
+ function getMutableRunCreate(dotOrder) {
192
173
  const segments = dotOrder.split(".").map((i) => {
193
174
  const [startTime, runId] = i.split("Z");
194
175
  return { startTime, runId };
195
176
  });
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(".");
210
177
  const traceId = segments[0].runId;
211
178
  const parentRunId = segments.at(-2)?.runId;
212
179
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
213
180
  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);
216
181
  return {
217
182
  id: runId,
218
183
  trace_id: traceId,
219
- dotted_order: updatedDotOrder,
184
+ dotted_order: dotOrder,
220
185
  parent_run_id: parentRunId,
221
- start_time: lastSegmentTime.toISOString(),
222
186
  };
223
187
  }
224
188
  function convertToTimestamp([seconds, nanoseconds]) {
@@ -810,15 +774,10 @@ export class AISDKExporter {
810
774
  }
811
775
  this.seenSpanInfo[task.id].dotOrder = taskDotOrder;
812
776
  if (!this.seenSpanInfo[task.id].sent) {
813
- const updated = {
777
+ sampled.push({
814
778
  ...task.run,
815
779
  ...getMutableRunCreate(taskDotOrder),
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);
780
+ });
822
781
  }
823
782
  this.seenSpanInfo[task.id].sent = true;
824
783
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.3.52",
3
+ "version": "0.3.53",
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": [