Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

langsmith

Package Overview
Dependencies
Maintainers
2
Versions
173
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

langsmith - npm Package Compare versions

Comparing version 0.1.20 to 0.1.21

2

dist/index.d.ts
export { Client } from "./client.js";
export type { Dataset, Example, TracerSession, Run, Feedback, } from "./schemas.js";
export { RunTree, type RunTreeConfig } from "./run_trees.js";
export declare const __version__ = "0.1.20";
export declare const __version__ = "0.1.21";
export { Client } from "./client.js";
export { RunTree } from "./run_trees.js";
// Update using yarn bump-version
export const __version__ = "0.1.20";
export const __version__ = "0.1.21";

@@ -68,3 +68,3 @@ import { BaseRun, KVMap } from "./schemas.js";

private static getDefaultConfig;
createChild(config: RunTreeConfig): Promise<RunTree>;
createChild(config: RunTreeConfig): RunTree;
end(outputs?: KVMap, error?: string, endTime?: number): Promise<void>;

@@ -71,0 +71,0 @@ private _convertToCreate;

@@ -208,3 +208,3 @@ import * as uuid from "uuid";

}
async createChild(config) {
createChild(config) {
const child = new RunTree({

@@ -220,5 +220,5 @@ ...config,

async end(outputs, error, endTime = Date.now()) {
this.outputs = outputs;
this.error = error;
this.end_time = endTime;
this.outputs = this.outputs ?? outputs;
this.error = this.error ?? error;
this.end_time = this.end_time ?? endTime;
}

@@ -225,0 +225,0 @@ async _convertToCreate(run, excludeChildRuns = true) {

import { RunTree, RunTreeConfig, RunnableConfigLike } from "./run_trees.js";
export type RunTreeLike = RunTree;
type SmartPromise<T> = T extends AsyncGenerator ? T : T extends Promise<unknown> ? T : Promise<T>;
type WrapArgReturnPair<Pair> = Pair extends [

@@ -7,5 +8,5 @@ infer Args extends any[],

] ? {
(...args: Args): Promise<Return>;
(...args: [runTree: RunTreeLike, ...rest: Args]): Promise<Return>;
(...args: [config: RunnableConfigLike, ...rest: Args]): Promise<Return>;
(...args: Args): SmartPromise<Return>;
(...args: [runTree: RunTreeLike, ...rest: Args]): SmartPromise<Return>;
(...args: [config: RunnableConfigLike, ...rest: Args]): SmartPromise<Return>;
} : never;

@@ -50,2 +51,3 @@ type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;

aggregator?: (args: any[]) => any;
argsConfigPath?: [number] | [number, string];
}): TraceableFunction<Func>;

@@ -52,0 +54,0 @@ /**

import { AsyncLocalStorage } from "async_hooks";
import { RunTree, isRunTree, isRunnableConfigLike, } from "./run_trees.js";
import { getEnvironmentVariable } from "./utils/env.js";
function isPromiseMethod(x) {
if (x === "then" || x === "catch" || x === "finally") {
return true;
}
return false;
}
const asyncLocalStorage = new AsyncLocalStorage();

@@ -33,10 +39,51 @@ const isAsyncIterable = (x) => x != null &&

export function traceable(wrappedFunc, config) {
const { aggregator, ...runTreeConfig } = config ?? {};
const traceableFunc = async (...args) => {
const { aggregator, argsConfigPath, ...runTreeConfig } = config ?? {};
const traceableFunc = (...args) => {
let currentRunTree;
let rawInputs;
const ensuredConfig = {
name: wrappedFunc.name || "<lambda>",
...runTreeConfig,
};
let ensuredConfig;
try {
let runtimeConfig;
if (argsConfigPath) {
const [index, path] = argsConfigPath;
if (index === args.length - 1 && !path) {
runtimeConfig = args.pop();
}
else if (index <= args.length &&
typeof args[index] === "object" &&
args[index] !== null) {
if (path) {
const { [path]: extracted, ...rest } = args[index];
runtimeConfig = extracted;
args[index] = rest;
}
else {
runtimeConfig = args[index];
args.splice(index, 1);
}
}
}
ensuredConfig = {
name: wrappedFunc.name || "<lambda>",
...runTreeConfig,
...runtimeConfig,
tags: [
...new Set([
...(runTreeConfig?.tags ?? []),
...(runtimeConfig?.tags ?? []),
]),
],
metadata: {
...runTreeConfig?.metadata,
...runtimeConfig?.metadata,
},
};
}
catch (err) {
console.warn(`Failed to extract runtime config from args for ${runTreeConfig?.name ?? wrappedFunc.name}`, err);
ensuredConfig = {
name: wrappedFunc.name || "<lambda>",
...runTreeConfig,
};
}
const previousRunTree = asyncLocalStorage.getStore();

@@ -52,3 +99,3 @@ if (isRunTree(args[0])) {

else if (previousRunTree !== undefined) {
currentRunTree = await previousRunTree.createChild(ensuredConfig);
currentRunTree = previousRunTree.createChild(ensuredConfig);
rawInputs = args;

@@ -78,39 +125,107 @@ }

}
const initialOutputs = currentRunTree?.outputs;
const initialError = currentRunTree?.error;
await currentRunTree?.postRun();
return new Promise((resolve, reject) => {
void asyncLocalStorage.run(currentRunTree, async () => {
try {
const rawOutput = await wrappedFunc(...rawInputs);
return asyncLocalStorage.run(currentRunTree, () => {
const postRunPromise = currentRunTree?.postRun();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let returnValue;
try {
returnValue = wrappedFunc(...rawInputs);
}
catch (err) {
returnValue = Promise.reject(err);
}
if (isAsyncIterable(returnValue)) {
// eslint-disable-next-line no-inner-declarations
async function* wrapOutputForTracing() {
let finished = false;
const chunks = [];
try {
for await (const chunk of returnValue) {
chunks.push(chunk);
yield chunk;
}
finished = true;
}
catch (e) {
await currentRunTree?.end(undefined, String(e));
throw e;
}
finally {
if (!finished) {
await currentRunTree?.end(undefined, "Cancelled");
}
let finalOutputs;
if (aggregator !== undefined) {
try {
finalOutputs = await aggregator(chunks);
}
catch (e) {
console.error(`[ERROR]: LangSmith aggregation failed: `, e);
finalOutputs = chunks;
}
}
else {
finalOutputs = chunks;
}
if (typeof finalOutputs === "object" &&
!Array.isArray(finalOutputs)) {
await currentRunTree?.end(finalOutputs);
}
else {
await currentRunTree?.end({ outputs: finalOutputs });
}
await postRunPromise;
await currentRunTree?.patchRun();
}
}
return wrapOutputForTracing();
}
const tracedPromise = new Promise((resolve, reject) => {
Promise.resolve(returnValue)
.then(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async (rawOutput) => {
if (isAsyncIterable(rawOutput)) {
// eslint-disable-next-line no-inner-declarations
async function* wrapOutputForTracing() {
let finished = false;
const chunks = [];
// TypeScript thinks this is unsafe
for await (const chunk of rawOutput) {
chunks.push(chunk);
yield chunk;
try {
// TypeScript thinks this is unsafe
for await (const chunk of rawOutput) {
chunks.push(chunk);
yield chunk;
}
finished = true;
}
let finalOutputs;
if (aggregator !== undefined) {
try {
finalOutputs = await aggregator(chunks);
catch (e) {
await currentRunTree?.end(undefined, String(e));
throw e;
}
finally {
if (!finished) {
await currentRunTree?.end(undefined, "Cancelled");
}
catch (e) {
console.error(`[ERROR]: LangSmith aggregation failed: `, e);
let finalOutputs;
if (aggregator !== undefined) {
try {
finalOutputs = await aggregator(chunks);
}
catch (e) {
console.error(`[ERROR]: LangSmith aggregation failed: `, e);
finalOutputs = chunks;
}
}
else {
finalOutputs = chunks;
}
if (typeof finalOutputs === "object" &&
!Array.isArray(finalOutputs)) {
await currentRunTree?.end(finalOutputs);
}
else {
await currentRunTree?.end({ outputs: finalOutputs });
}
await postRunPromise;
await currentRunTree?.patchRun();
}
else {
finalOutputs = chunks;
}
if (typeof finalOutputs === "object" &&
!Array.isArray(finalOutputs)) {
await currentRunTree?.end(finalOutputs);
}
else {
await currentRunTree?.end({ outputs: finalOutputs });
}
await currentRunTree?.patchRun();
}

@@ -120,30 +235,33 @@ return resolve(wrapOutputForTracing());

else {
const outputs = isKVMap(rawOutput)
? rawOutput
: { outputs: rawOutput };
if (initialOutputs === currentRunTree?.outputs) {
await currentRunTree?.end(outputs);
try {
await currentRunTree?.end(isKVMap(rawOutput) ? rawOutput : { outputs: rawOutput });
await postRunPromise;
await currentRunTree?.patchRun();
}
else {
if (currentRunTree !== undefined) {
currentRunTree.end_time = Date.now();
}
finally {
// eslint-disable-next-line no-unsafe-finally
return rawOutput;
}
await currentRunTree?.patchRun();
return resolve(rawOutput);
}
}
catch (error) {
if (initialError === currentRunTree?.error) {
await currentRunTree?.end(initialOutputs, String(error));
}
else {
if (currentRunTree !== undefined) {
currentRunTree.end_time = Date.now();
}
}
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async (error) => {
await currentRunTree?.end(undefined, String(error));
await postRunPromise;
await currentRunTree?.patchRun();
reject(error);
}
throw error;
})
.then(resolve, reject);
});
if (typeof returnValue !== "object" || returnValue === null) {
return tracedPromise;
}
return new Proxy(returnValue, {
get(target, prop, receiver) {
if (isPromiseMethod(prop)) {
return tracedPromise[prop].bind(tracedPromise);
}
return Reflect.get(target, prop, receiver);
},
});
});

@@ -150,0 +268,0 @@ };

import pRetry from "p-retry";
import PQueueMod from "p-queue";
const STATUS_NO_RETRY = [
400,
401,
403,
404,
405,
406,
407,
400, // Bad Request
401, // Unauthorized
403, // Forbidden
404, // Not Found
405, // Method Not Allowed
406, // Not Acceptable
407, // Proxy Authentication Required
408, // Request Timeout

@@ -57,4 +57,12 @@ ];

this.maxRetries = params.maxRetries ?? 6;
const PQueue = "default" in PQueueMod ? PQueueMod.default : PQueueMod;
this.queue = new PQueue({ concurrency: this.maxConcurrency });
if ("default" in PQueueMod) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.queue = new PQueueMod.default({
concurrency: this.maxConcurrency,
});
}
else {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.queue = new PQueueMod({ concurrency: this.maxConcurrency });
}
this.onFailedResponseHook = params?.onFailedResponseHook;

@@ -61,0 +69,0 @@ }

@@ -1,2 +0,3 @@

import type { OpenAI } from "openai";
import { OpenAI } from "openai";
import type { APIPromise } from "openai/core";
import type { Client, RunTreeConfig } from "../index.js";

@@ -15,27 +16,25 @@ import { type RunnableConfigLike } from "../run_trees.js";

};
type PatchedOpenAIClient<T extends OpenAIType> = {
[P in keyof T]: T[P];
} & {
chat: {
completions: {
type PatchedOpenAIClient<T extends OpenAIType> = T & {
chat: T["chat"] & {
completions: T["chat"]["completions"] & {
create: {
(arg: OpenAI.ChatCompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
langsmithExtra?: RunnableConfigLike | RunTreeLike;
}): Promise<AsyncGenerator<OpenAI.ChatCompletionChunk>>;
}): APIPromise<AsyncGenerator<OpenAI.ChatCompletionChunk>>;
} & {
(arg: OpenAI.ChatCompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
langsmithExtra?: RunnableConfigLike | RunTreeLike;
}): Promise<OpenAI.ChatCompletionChunk>;
}): APIPromise<OpenAI.ChatCompletionChunk>;
};
};
};
completions: {
completions: T["completions"] & {
create: {
(arg: OpenAI.CompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
langsmithExtra?: RunnableConfigLike | RunTreeLike;
}): Promise<AsyncGenerator<OpenAI.Completion>>;
}): APIPromise<AsyncGenerator<OpenAI.Completion>>;
} & {
(arg: OpenAI.CompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
langsmithExtra?: RunnableConfigLike | RunTreeLike;
}): Promise<OpenAI.Completion>;
}): APIPromise<OpenAI.Completion>;
};

@@ -42,0 +41,0 @@ };

import { traceable } from "../traceable.js";
function _combineChatCompletionChoices(choices) {
function _combineChatCompletionChoices(choices
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) {
const reversedChoices = choices.slice().reverse();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const message = {

@@ -73,22 +76,39 @@ role: "assistant",

}
async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig) {
if (args[1]?.langsmithExtra !== undefined) {
const { langsmithExtra, ...openAIOptions } = args[1];
const wrappedMethod = traceable(openAIMethod, {
...defaultRunConfig,
...langsmithExtra,
});
const finalArgs = [args[0]];
if (args.length > 2) {
finalArgs.push(openAIOptions);
finalArgs.push(args.slice(2));
const chatAggregator = (chunks) => {
if (!chunks || chunks.length === 0) {
return { choices: [{ message: { role: "assistant", content: "" } }] };
}
const choicesByIndex = {};
for (const chunk of chunks) {
for (const choice of chunk.choices) {
if (choicesByIndex[choice.index] === undefined) {
choicesByIndex[choice.index] = [];
}
choicesByIndex[choice.index].push(choice);
}
else if (Object.keys(openAIOptions).length !== 0) {
finalArgs.push(openAIOptions);
}
const aggregatedOutput = chunks[chunks.length - 1];
aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
return aggregatedOutput;
};
const textAggregator = (allChunks
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => {
if (allChunks.length === 0) {
return { choices: [{ text: "" }] };
}
const allContent = [];
for (const chunk of allChunks) {
const content = chunk.choices[0].text;
if (content != null) {
allContent.push(content);
}
return wrappedMethod(...finalArgs);
}
const wrappedMethod = traceable(openAIMethod, defaultRunConfig);
return wrappedMethod(...args);
}
const content = allContent.join("");
const aggregatedOutput = allChunks[allChunks.length - 1];
aggregatedOutput.choices = [
{ ...aggregatedOutput.choices[0], text: content },
];
return aggregatedOutput;
};
/**

@@ -119,57 +139,16 @@ * Wraps an OpenAI client's completion methods, enabling automatic LangSmith

export const wrapOpenAI = (openai, options) => {
const originalChatCompletionsFn = openai.chat.completions.create.bind(openai.chat.completions);
openai.chat.completions.create = async (...args) => {
const aggregator = (chunks) => {
if (!chunks || chunks.length === 0) {
return { choices: [{ message: { role: "assistant", content: "" } }] };
}
const choicesByIndex = {};
for (const chunk of chunks) {
for (const choice of chunk.choices) {
if (choicesByIndex[choice.index] === undefined) {
choicesByIndex[choice.index] = [];
}
choicesByIndex[choice.index].push(choice);
}
}
const aggregatedOutput = chunks[chunks.length - 1];
aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
return aggregatedOutput;
};
const defaultRunConfig = {
name: "ChatOpenAI",
run_type: "llm",
aggregator,
...options,
};
return extractLangSmithExtraAndCall(originalChatCompletionsFn, args, defaultRunConfig);
};
const originalCompletionsFn = openai.completions.create.bind(openai.chat.completions);
openai.completions.create = async (...args) => {
const aggregator = (allChunks) => {
if (allChunks.length === 0) {
return { choices: [{ text: "" }] };
}
const allContent = [];
for (const chunk of allChunks) {
const content = chunk.choices[0].text;
if (content != null) {
allContent.push(content);
}
}
const content = allContent.join("");
const aggregatedOutput = allChunks[allChunks.length - 1];
aggregatedOutput.choices = [
{ ...aggregatedOutput.choices[0], text: content },
];
return aggregatedOutput;
};
const defaultRunConfig = {
name: "OpenAI",
run_type: "llm",
aggregator,
...options,
};
return extractLangSmithExtraAndCall(originalCompletionsFn, args, defaultRunConfig);
};
openai.chat.completions.create = traceable(openai.chat.completions.create.bind(openai.chat.completions), {
name: "ChatOpenAI",
run_type: "llm",
aggregator: chatAggregator,
argsConfigPath: [1, "langsmithExtra"],
...options,
});
openai.completions.create = traceable(openai.completions.create.bind(openai.completions), {
name: "OpenAI",
run_type: "llm",
aggregator: textAggregator,
argsConfigPath: [1, "langsmithExtra"],
...options,
});
return openai;

@@ -182,3 +161,3 @@ };

if (typeof originalValue === "function") {
return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options));
}

@@ -185,0 +164,0 @@ else if (originalValue != null &&

{
"name": "langsmith",
"version": "0.1.20",
"version": "0.1.21",
"description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",

@@ -50,4 +50,4 @@ "packageManager": "yarn@1.22.19",

"clean": "rm -rf dist/ && node scripts/create-entrypoints.js clean",
"build:esm": "tsc --outDir dist/ && rm -rf dist/tests dist/**/tests",
"build:cjs": "tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rm -r dist-cjs",
"build:esm": "rm -f src/package.json && tsc --outDir dist/ && rm -rf dist/tests dist/**/tests",
"build:cjs": "echo '{}' > src/package.json && tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rm -r dist-cjs src/package.json",
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests --testPathIgnorePatterns='\\.int\\.test.[tj]s' --testTimeout 30000",

@@ -108,3 +108,3 @@ "test:integration": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000",

"ts-node": "^10.9.1",
"typescript": "^5.0.4"
"typescript": "^5.4.5"
},

@@ -111,0 +111,0 @@ "peerDependencies": {

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

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc