langsmith
Advanced tools
Comparing version 0.2.15-rc.8 to 0.2.15
@@ -167,10 +167,2 @@ import { AsyncCallerParams } from "./utils/async_caller.js"; | ||
}; | ||
export type CreateProjectParams = { | ||
projectName: string; | ||
description?: string | null; | ||
metadata?: RecordStringAny | null; | ||
upsert?: boolean; | ||
projectExtra?: RecordStringAny | null; | ||
referenceDatasetId?: string | null; | ||
}; | ||
type AutoBatchQueueItem = { | ||
@@ -407,3 +399,10 @@ action: "create" | "update"; | ||
}): Promise<Example[]>; | ||
createProject({ projectName, description, metadata, upsert, projectExtra, referenceDatasetId, }: CreateProjectParams): Promise<TracerSession>; | ||
createProject({ projectName, description, metadata, upsert, projectExtra, referenceDatasetId, }: { | ||
projectName: string; | ||
description?: string | null; | ||
metadata?: RecordStringAny | null; | ||
upsert?: boolean; | ||
projectExtra?: RecordStringAny | null; | ||
referenceDatasetId?: string | null; | ||
}): Promise<TracerSession>; | ||
updateProject(projectId: string, { name, description, metadata, projectExtra, endTime, }: { | ||
@@ -719,2 +718,15 @@ name?: string | null; | ||
getRunFromAnnotationQueue(queueId: string, index: number): Promise<RunWithAnnotationQueueInfo>; | ||
/** | ||
* Delete a run from an an annotation queue. | ||
* @param queueId - The ID of the annotation queue to delete the run from | ||
* @param queueRunId - The ID of the run to delete from the annotation queue | ||
*/ | ||
deleteRunFromAnnotationQueue(queueId: string, queueRunId: string): Promise<void>; | ||
/** | ||
* Get the size of an annotation queue. | ||
* @param queueId - The ID of the annotation queue | ||
*/ | ||
getSizeFromAnnotationQueue(queueId: string): Promise<{ | ||
size: number; | ||
}>; | ||
protected _currentTenantIsOwner(owner: string): Promise<boolean>; | ||
@@ -721,0 +733,0 @@ protected _ownerConflictError(action: string, owner: string): Promise<Error>; |
@@ -5,2 +5,2 @@ export { Client, type ClientConfig, type LangSmithTracingClientInterface, } from "./client.js"; | ||
export { overrideFetchImplementation } from "./singletons/fetch.js"; | ||
export declare const __version__ = "0.2.15-rc.8"; | ||
export declare const __version__ = "0.2.15"; |
@@ -5,2 +5,2 @@ export { Client, } from "./client.js"; | ||
// Update using yarn bump-version | ||
export const __version__ = "0.2.15-rc.8"; | ||
export const __version__ = "0.2.15"; |
@@ -83,3 +83,3 @@ import { Attachments, BaseRun, KVMap, RunCreate } from "./schemas.js"; | ||
private static getDefaultConfig; | ||
static getSharedClient(): Client; | ||
private static getSharedClient; | ||
createChild(config: RunTreeConfig): RunTree; | ||
@@ -86,0 +86,0 @@ end(outputs?: KVMap, error?: string, endTime?: number, metadata?: KVMap): Promise<void>; |
@@ -38,3 +38,3 @@ import { isRunTree } from "../run_trees.js"; | ||
"", | ||
"Please make sure you are calling this method within a traceable function and that tracing is enabled.", | ||
"Please make sure you are calling this method within a traceable function or the tracing is enabled.", | ||
].join("\n")); | ||
@@ -41,0 +41,0 @@ } |
import { Client, RunTree } from "./index.js"; | ||
import { v5 as uuid5, v4 as uuid4 } from "uuid"; | ||
import { v5 as uuid5 } from "uuid"; | ||
import { getCurrentRunTree } from "./singletons/traceable.js"; | ||
@@ -107,11 +107,45 @@ import { getLangSmithEnvironmentVariable, getEnvironmentVariable, } from "./utils/env.js"; | ||
} | ||
function convertToDottedOrderFormat([seconds, nanoseconds], runId, executionOrder) { | ||
function getDotOrder(item) { | ||
const { startTime: [seconds, nanoseconds], id: runId, executionOrder, } = item; | ||
// Date only has millisecond precision, so we use the microseconds to break | ||
// possible ties, avoiding incorrect run order | ||
const ms = Number(String(nanoseconds).slice(0, 3)); | ||
const ns = String(Number(String(nanoseconds).slice(3, 6)) + executionOrder) | ||
.padStart(3, "0") | ||
.slice(0, 3); | ||
const nanosecondString = String(nanoseconds).padStart(9, "0"); | ||
const msFull = Number(nanosecondString.slice(0, 6)) + executionOrder; | ||
const msString = String(msFull).padStart(6, "0"); | ||
const ms = Number(msString.slice(0, -3)); | ||
const ns = msString.slice(-3); | ||
return (stripNonAlphanumeric(`${new Date(seconds * 1000 + ms).toISOString().slice(0, -1)}${ns}Z`) + runId); | ||
} | ||
function joinDotOrder(...segments) { | ||
return segments.filter(Boolean).join("."); | ||
} | ||
function removeDotOrder(dotOrder, ...ids) { | ||
return dotOrder | ||
.split(".") | ||
.filter((i) => !ids.some((id) => i.includes(id))) | ||
.join("."); | ||
} | ||
function reparentDotOrder(dotOrder, sourceRunId, parentDotOrder) { | ||
const segments = dotOrder.split("."); | ||
const sourceIndex = segments.findIndex((i) => i.includes(sourceRunId)); | ||
if (sourceIndex === -1) | ||
return dotOrder; | ||
return joinDotOrder(...parentDotOrder.split("."), ...segments.slice(sourceIndex)); | ||
} | ||
function getMutableRunCreate(dotOrder) { | ||
const segments = dotOrder.split(".").map((i) => { | ||
const [startTime, runId] = i.split("Z"); | ||
return { startTime, runId }; | ||
}); | ||
const traceId = segments[0].runId; | ||
const parentRunId = segments.at(-2)?.runId; | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
const runId = segments.at(-1).runId; | ||
return { | ||
id: runId, | ||
trace_id: traceId, | ||
dotted_order: dotOrder, | ||
parent_run_id: parentRunId, | ||
}; | ||
} | ||
function convertToTimestamp([seconds, nanoseconds]) { | ||
@@ -257,2 +291,4 @@ const ms = String(nanoseconds).slice(0, 3); | ||
parseInteropFromMetadata(span) { | ||
if (!this.isRootRun(span)) | ||
return undefined; | ||
const userTraceId = this.getSpanAttributeKey(span, RUN_ID_METADATA_KEY.output); | ||
@@ -273,3 +309,3 @@ const parentTrace = this.getSpanAttributeKey(span, TRACE_METADATA_KEY.output); | ||
if (userTraceId) | ||
return { type: "user", userTraceId }; | ||
return { type: "user", userRunId: userTraceId }; | ||
return undefined; | ||
@@ -279,6 +315,2 @@ } | ||
getRunCreate(span) { | ||
const runId = uuid5(span.spanContext().spanId, RUN_ID_NAMESPACE); | ||
const parentRunId = span.parentSpanId | ||
? uuid5(span.parentSpanId, RUN_ID_NAMESPACE) | ||
: undefined; | ||
const asRunCreate = (rawConfig) => { | ||
@@ -311,4 +343,2 @@ const aiMetadata = Object.keys(span.attributes) | ||
name, | ||
id: runId, | ||
parent_run_id: parentRunId, | ||
extra: { | ||
@@ -545,15 +575,7 @@ ...rawConfig.extra, | ||
const runId = uuid5(spanId, RUN_ID_NAMESPACE); | ||
let parentRunId = parentId | ||
const parentRunId = parentId | ||
? uuid5(parentId, RUN_ID_NAMESPACE) | ||
: undefined; | ||
// in LangSmith we currently only support certain spans | ||
// which may be deeply nested within other traces | ||
if (this.isRootRun(span)) | ||
parentRunId = undefined; | ||
const traceMap = this.traceByMap[traceId]; | ||
const run = this.getRunCreate(span); | ||
if (!run) { | ||
this.logDebug("skipping span", span); | ||
continue; | ||
} | ||
traceMap.relativeExecutionOrder[parentRunId ?? ROOT] ??= -1; | ||
@@ -563,6 +585,6 @@ traceMap.relativeExecutionOrder[parentRunId ?? ROOT] += 1; | ||
id: runId, | ||
parentId: parentRunId, | ||
startTime: span.startTime, | ||
run, | ||
sent: false, | ||
interop: this.parseInteropFromMetadata(span), | ||
executionOrder: traceMap.relativeExecutionOrder[parentRunId ?? ROOT], | ||
@@ -574,6 +596,5 @@ }; | ||
traceMap.childMap[parentRunId ?? ROOT].push(traceMap.nodeMap[runId]); | ||
traceMap.interop = this.parseInteropFromMetadata(span); | ||
} | ||
// We separate `id`, | ||
const sampled = []; | ||
const actions = []; | ||
for (const traceId of Object.keys(this.traceByMap)) { | ||
@@ -583,4 +604,3 @@ const traceMap = this.traceByMap[traceId]; | ||
item, | ||
dottedOrder: convertToDottedOrderFormat(item.startTime, item.id, item.executionOrder), | ||
traceId: item.id, | ||
dotOrder: getDotOrder(item), | ||
})) ?? []; | ||
@@ -594,67 +614,53 @@ const seen = new Set(); | ||
if (!task.item.sent) { | ||
let override = { | ||
id: task.item.id, | ||
parent_run_id: task.item.parentId, | ||
dotted_order: task.dottedOrder, | ||
trace_id: task.traceId, | ||
}; | ||
if (traceMap.interop) { | ||
// attach the run to a parent run tree | ||
// - id: preserve | ||
// - parent_run_id: use existing parent run id or hook to the provided run tree | ||
// - dotted_order: append to the dotted_order of the parent run tree | ||
// - trace_id: use from the existing run tree | ||
if (traceMap.interop.type === "traceable") { | ||
override = { | ||
id: override.id, | ||
parent_run_id: override.parent_run_id ?? traceMap.interop.parentRunTree.id, | ||
dotted_order: [ | ||
traceMap.interop.parentRunTree.dotted_order, | ||
override.dotted_order, | ||
] | ||
.filter(Boolean) | ||
.join("."), | ||
trace_id: traceMap.interop.parentRunTree.trace_id, | ||
}; | ||
if (task.item.run != null) { | ||
if (task.item.interop?.type === "user") { | ||
actions.push({ | ||
type: "rename", | ||
sourceRunId: task.item.id, | ||
targetRunId: task.item.interop.userRunId, | ||
}); | ||
} | ||
else if (traceMap.interop.type === "user") { | ||
// Allow user to specify custom trace ID = run ID of the root run | ||
// - id: use user provided run ID if root run, otherwise preserve | ||
// - parent_run_id: use user provided run ID if root run, otherwise preserve | ||
// - dotted_order: replace the trace_id with the user provided run ID | ||
// - trace_id: use user provided run ID | ||
const userTraceId = traceMap.interop.userTraceId ?? uuid4(); | ||
override = { | ||
id: override.id === override.trace_id ? userTraceId : override.id, | ||
parent_run_id: override.parent_run_id === override.trace_id | ||
? userTraceId | ||
: override.parent_run_id, | ||
dotted_order: override.dotted_order.replace(override.trace_id, userTraceId), | ||
trace_id: userTraceId, | ||
}; | ||
if (task.item.interop?.type === "traceable") { | ||
actions.push({ | ||
type: "reparent", | ||
runId: task.item.id, | ||
parentDotOrder: task.item.interop.parentRunTree.dotted_order, | ||
}); | ||
} | ||
let dotOrder = task.dotOrder; | ||
for (const action of actions) { | ||
if (action.type === "delete") { | ||
dotOrder = removeDotOrder(dotOrder, action.runId); | ||
} | ||
if (action.type === "reparent") { | ||
dotOrder = reparentDotOrder(dotOrder, action.runId, action.parentDotOrder); | ||
} | ||
if (action.type === "rename") { | ||
dotOrder = dotOrder.replace(action.sourceRunId, action.targetRunId); | ||
} | ||
} | ||
sampled.push({ | ||
...task.item.run, | ||
...getMutableRunCreate(dotOrder), | ||
}); | ||
} | ||
sampled.push([override, task.item.run]); | ||
else { | ||
actions.push({ type: "delete", runId: task.item.id }); | ||
} | ||
task.item.sent = true; | ||
} | ||
const children = traceMap.childMap[task.item.id] ?? []; | ||
queue.push(...children.map((child) => { | ||
return { | ||
item: child, | ||
dottedOrder: [ | ||
task.dottedOrder, | ||
convertToDottedOrderFormat(child.startTime, child.id, child.executionOrder), | ||
].join("."), | ||
traceId: task.traceId, | ||
}; | ||
})); | ||
queue.push(...children.map((item) => ({ | ||
item, | ||
dotOrder: joinDotOrder(task.dotOrder, getDotOrder(item)), | ||
}))); | ||
} | ||
} | ||
this.logDebug(`sampled runs to be sent to LangSmith`, sampled); | ||
Promise.all(sampled.map(([override, value]) => this.client.createRun({ ...value, ...override }))).then(() => resultCallback({ code: 0 }), (error) => resultCallback({ code: 1, error })); | ||
Promise.all(sampled.map((run) => this.client.createRun(run))).then(() => resultCallback({ code: 0 }), (error) => resultCallback({ code: 1, error })); | ||
} | ||
async shutdown() { | ||
// find nodes which are incomplete | ||
const incompleteNodes = Object.values(this.traceByMap).flatMap((trace) => Object.values(trace.nodeMap).filter((i) => !i.sent)); | ||
this.logDebug("shutting down", { incompleteNodes: incompleteNodes.length }); | ||
const incompleteNodes = Object.values(this.traceByMap).flatMap((trace) => Object.values(trace.nodeMap).filter((i) => !i.sent && i.run != null)); | ||
this.logDebug("shutting down", { incompleteNodes }); | ||
if (incompleteNodes.length > 0) { | ||
@@ -661,0 +667,0 @@ console.warn("Some incomplete nodes were found before shutdown and not sent to LangSmith."); |
{ | ||
"name": "langsmith", | ||
"version": "0.2.15-rc.8", | ||
"version": "0.2.15", | ||
"description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.", | ||
@@ -36,6 +36,2 @@ "packageManager": "yarn@1.22.19", | ||
"langchain.d.cts", | ||
"jest.cjs", | ||
"jest.js", | ||
"jest.d.ts", | ||
"jest.d.cts", | ||
"vercel.cjs", | ||
@@ -45,6 +41,2 @@ "vercel.js", | ||
"vercel.d.cts", | ||
"vitest.cjs", | ||
"vitest.js", | ||
"vitest.d.ts", | ||
"vitest.d.cts", | ||
"wrappers.cjs", | ||
@@ -122,3 +114,3 @@ "wrappers.js", | ||
"devDependencies": { | ||
"@ai-sdk/openai": "^0.0.68", | ||
"@ai-sdk/openai": "^1.0.13", | ||
"@babel/preset-env": "^7.22.4", | ||
@@ -130,2 +122,3 @@ "@faker-js/faker": "^8.4.1", | ||
"@langchain/openai": "^0.3.11", | ||
"@opentelemetry/api": "^1.9.0", | ||
"@opentelemetry/sdk-trace-base": "^1.26.0", | ||
@@ -137,3 +130,3 @@ "@opentelemetry/sdk-trace-node": "^1.26.0", | ||
"@typescript-eslint/parser": "^5.59.8", | ||
"ai": "^3.4.17", | ||
"ai": "^4.0.27", | ||
"babel-jest": "^29.5.0", | ||
@@ -155,3 +148,2 @@ "cross-env": "^7.0.3", | ||
"typescript": "^5.4.5", | ||
"vitest": "^2.1.8", | ||
"zod": "^3.23.8" | ||
@@ -246,11 +238,2 @@ }, | ||
}, | ||
"./jest": { | ||
"types": { | ||
"import": "./jest.d.ts", | ||
"require": "./jest.d.cts", | ||
"default": "./jest.d.ts" | ||
}, | ||
"import": "./jest.js", | ||
"require": "./jest.cjs" | ||
}, | ||
"./vercel": { | ||
@@ -265,11 +248,2 @@ "types": { | ||
}, | ||
"./vitest": { | ||
"types": { | ||
"import": "./vitest.d.ts", | ||
"require": "./vitest.d.cts", | ||
"default": "./vitest.d.ts" | ||
}, | ||
"import": "./vitest.js", | ||
"require": "./vitest.cjs" | ||
}, | ||
"./wrappers": { | ||
@@ -276,0 +250,0 @@ "types": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
800373
211
20803