langsmith 0.1.20 → 0.1.22

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.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/client.cjs +71 -31
  3. package/dist/client.d.ts +7 -3
  4. package/dist/client.js +48 -8
  5. package/dist/evaluation/_random_name.cjs +730 -0
  6. package/dist/evaluation/_random_name.d.ts +5 -0
  7. package/dist/evaluation/_random_name.js +726 -0
  8. package/dist/evaluation/_runner.cjs +709 -0
  9. package/dist/evaluation/_runner.d.ts +158 -0
  10. package/dist/evaluation/_runner.js +705 -0
  11. package/dist/evaluation/evaluator.cjs +86 -0
  12. package/dist/evaluation/evaluator.d.ts +31 -27
  13. package/dist/evaluation/evaluator.js +83 -1
  14. package/dist/evaluation/index.cjs +3 -1
  15. package/dist/evaluation/index.d.ts +1 -0
  16. package/dist/evaluation/index.js +1 -0
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/run_trees.cjs +4 -4
  21. package/dist/run_trees.d.ts +2 -1
  22. package/dist/run_trees.js +4 -4
  23. package/dist/schemas.d.ts +22 -1
  24. package/dist/traceable.cjs +237 -62
  25. package/dist/traceable.d.ts +7 -3
  26. package/dist/traceable.js +235 -61
  27. package/dist/utils/_git.cjs +72 -0
  28. package/dist/utils/_git.d.ts +14 -0
  29. package/dist/utils/_git.js +67 -0
  30. package/dist/utils/_uuid.cjs +33 -0
  31. package/dist/utils/_uuid.d.ts +1 -0
  32. package/dist/utils/_uuid.js +6 -0
  33. package/dist/utils/async_caller.cjs +17 -9
  34. package/dist/utils/async_caller.js +17 -9
  35. package/dist/utils/atee.cjs +24 -0
  36. package/dist/utils/atee.d.ts +1 -0
  37. package/dist/utils/atee.js +20 -0
  38. package/dist/wrappers/openai.cjs +53 -74
  39. package/dist/wrappers/openai.d.ts +10 -11
  40. package/dist/wrappers/openai.js +53 -74
  41. package/package.json +4 -4
@@ -0,0 +1,20 @@
1
+ export function atee(iter, length = 2) {
2
+ const buffers = Array.from({ length }, () => []);
3
+ return buffers.map(async function* makeIter(buffer) {
4
+ while (true) {
5
+ if (buffer.length === 0) {
6
+ const result = await iter.next();
7
+ for (const buffer of buffers) {
8
+ buffer.push(result);
9
+ }
10
+ }
11
+ else if (buffer[0].done) {
12
+ return;
13
+ }
14
+ else {
15
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16
+ yield buffer.shift().value;
17
+ }
18
+ }
19
+ });
20
+ }
@@ -2,8 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.wrapSDK = exports.wrapOpenAI = void 0;
4
4
  const traceable_js_1 = require("../traceable.cjs");
5
- function _combineChatCompletionChoices(choices) {
5
+ function _combineChatCompletionChoices(choices
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ ) {
6
8
  const reversedChoices = choices.slice().reverse();
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
10
  const message = {
8
11
  role: "assistant",
9
12
  content: "",
@@ -73,26 +76,43 @@ function _combineChatCompletionChoices(choices) {
73
76
  message: message,
74
77
  };
75
78
  }
76
- async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig) {
77
- if (args[1]?.langsmithExtra !== undefined) {
78
- const { langsmithExtra, ...openAIOptions } = args[1];
79
- const wrappedMethod = (0, traceable_js_1.traceable)(openAIMethod, {
80
- ...defaultRunConfig,
81
- ...langsmithExtra,
82
- });
83
- const finalArgs = [args[0]];
84
- if (args.length > 2) {
85
- finalArgs.push(openAIOptions);
86
- finalArgs.push(args.slice(2));
79
+ const chatAggregator = (chunks) => {
80
+ if (!chunks || chunks.length === 0) {
81
+ return { choices: [{ message: { role: "assistant", content: "" } }] };
82
+ }
83
+ const choicesByIndex = {};
84
+ for (const chunk of chunks) {
85
+ for (const choice of chunk.choices) {
86
+ if (choicesByIndex[choice.index] === undefined) {
87
+ choicesByIndex[choice.index] = [];
88
+ }
89
+ choicesByIndex[choice.index].push(choice);
87
90
  }
88
- else if (Object.keys(openAIOptions).length !== 0) {
89
- finalArgs.push(openAIOptions);
91
+ }
92
+ const aggregatedOutput = chunks[chunks.length - 1];
93
+ aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
94
+ return aggregatedOutput;
95
+ };
96
+ const textAggregator = (allChunks
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
+ ) => {
99
+ if (allChunks.length === 0) {
100
+ return { choices: [{ text: "" }] };
101
+ }
102
+ const allContent = [];
103
+ for (const chunk of allChunks) {
104
+ const content = chunk.choices[0].text;
105
+ if (content != null) {
106
+ allContent.push(content);
90
107
  }
91
- return wrappedMethod(...finalArgs);
92
108
  }
93
- const wrappedMethod = (0, traceable_js_1.traceable)(openAIMethod, defaultRunConfig);
94
- return wrappedMethod(...args);
95
- }
109
+ const content = allContent.join("");
110
+ const aggregatedOutput = allChunks[allChunks.length - 1];
111
+ aggregatedOutput.choices = [
112
+ { ...aggregatedOutput.choices[0], text: content },
113
+ ];
114
+ return aggregatedOutput;
115
+ };
96
116
  /**
97
117
  * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
98
118
  * tracing. Method signatures are unchanged, with the exception that you can pass
@@ -118,61 +138,20 @@ async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig
118
138
  * ```
119
139
  */
120
140
  const wrapOpenAI = (openai, options) => {
121
- const originalChatCompletionsFn = openai.chat.completions.create.bind(openai.chat.completions);
122
- openai.chat.completions.create = async (...args) => {
123
- const aggregator = (chunks) => {
124
- if (!chunks || chunks.length === 0) {
125
- return { choices: [{ message: { role: "assistant", content: "" } }] };
126
- }
127
- const choicesByIndex = {};
128
- for (const chunk of chunks) {
129
- for (const choice of chunk.choices) {
130
- if (choicesByIndex[choice.index] === undefined) {
131
- choicesByIndex[choice.index] = [];
132
- }
133
- choicesByIndex[choice.index].push(choice);
134
- }
135
- }
136
- const aggregatedOutput = chunks[chunks.length - 1];
137
- aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
138
- return aggregatedOutput;
139
- };
140
- const defaultRunConfig = {
141
- name: "ChatOpenAI",
142
- run_type: "llm",
143
- aggregator,
144
- ...options,
145
- };
146
- return extractLangSmithExtraAndCall(originalChatCompletionsFn, args, defaultRunConfig);
147
- };
148
- const originalCompletionsFn = openai.completions.create.bind(openai.chat.completions);
149
- openai.completions.create = async (...args) => {
150
- const aggregator = (allChunks) => {
151
- if (allChunks.length === 0) {
152
- return { choices: [{ text: "" }] };
153
- }
154
- const allContent = [];
155
- for (const chunk of allChunks) {
156
- const content = chunk.choices[0].text;
157
- if (content != null) {
158
- allContent.push(content);
159
- }
160
- }
161
- const content = allContent.join("");
162
- const aggregatedOutput = allChunks[allChunks.length - 1];
163
- aggregatedOutput.choices = [
164
- { ...aggregatedOutput.choices[0], text: content },
165
- ];
166
- return aggregatedOutput;
167
- };
168
- const defaultRunConfig = {
169
- name: "OpenAI",
170
- run_type: "llm",
171
- aggregator,
172
- ...options,
173
- };
174
- return extractLangSmithExtraAndCall(originalCompletionsFn, args, defaultRunConfig);
175
- };
141
+ openai.chat.completions.create = (0, traceable_js_1.traceable)(openai.chat.completions.create.bind(openai.chat.completions), {
142
+ name: "ChatOpenAI",
143
+ run_type: "llm",
144
+ aggregator: chatAggregator,
145
+ argsConfigPath: [1, "langsmithExtra"],
146
+ ...options,
147
+ });
148
+ openai.completions.create = (0, traceable_js_1.traceable)(openai.completions.create.bind(openai.completions), {
149
+ name: "OpenAI",
150
+ run_type: "llm",
151
+ aggregator: textAggregator,
152
+ argsConfigPath: [1, "langsmithExtra"],
153
+ ...options,
154
+ });
176
155
  return openai;
177
156
  };
178
157
  exports.wrapOpenAI = wrapOpenAI;
@@ -181,7 +160,7 @@ const _wrapClient = (sdk, runName, options) => {
181
160
  get(target, propKey, receiver) {
182
161
  const originalValue = target[propKey];
183
162
  if (typeof originalValue === "function") {
184
- return (0, traceable_js_1.traceable)(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
163
+ return (0, traceable_js_1.traceable)(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options));
185
164
  }
186
165
  else if (originalValue != null &&
187
166
  !Array.isArray(originalValue) &&
@@ -1,4 +1,5 @@
1
- import type { OpenAI } from "openai";
1
+ import { OpenAI } from "openai";
2
+ import type { APIPromise } from "openai/core";
2
3
  import type { Client, RunTreeConfig } from "../index.js";
3
4
  import { type RunnableConfigLike } from "../run_trees.js";
4
5
  import { type RunTreeLike } from "../traceable.js";
@@ -12,31 +13,29 @@ type OpenAIType = {
12
13
  create: (...args: any[]) => any;
13
14
  };
14
15
  };
15
- type PatchedOpenAIClient<T extends OpenAIType> = {
16
- [P in keyof T]: T[P];
17
- } & {
18
- chat: {
19
- completions: {
16
+ type PatchedOpenAIClient<T extends OpenAIType> = T & {
17
+ chat: T["chat"] & {
18
+ completions: T["chat"]["completions"] & {
20
19
  create: {
21
20
  (arg: OpenAI.ChatCompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
22
21
  langsmithExtra?: RunnableConfigLike | RunTreeLike;
23
- }): Promise<AsyncGenerator<OpenAI.ChatCompletionChunk>>;
22
+ }): APIPromise<AsyncGenerator<OpenAI.ChatCompletionChunk>>;
24
23
  } & {
25
24
  (arg: OpenAI.ChatCompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
26
25
  langsmithExtra?: RunnableConfigLike | RunTreeLike;
27
- }): Promise<OpenAI.ChatCompletionChunk>;
26
+ }): APIPromise<OpenAI.ChatCompletionChunk>;
28
27
  };
29
28
  };
30
29
  };
31
- completions: {
30
+ completions: T["completions"] & {
32
31
  create: {
33
32
  (arg: OpenAI.CompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
34
33
  langsmithExtra?: RunnableConfigLike | RunTreeLike;
35
- }): Promise<AsyncGenerator<OpenAI.Completion>>;
34
+ }): APIPromise<AsyncGenerator<OpenAI.Completion>>;
36
35
  } & {
37
36
  (arg: OpenAI.CompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
38
37
  langsmithExtra?: RunnableConfigLike | RunTreeLike;
39
- }): Promise<OpenAI.Completion>;
38
+ }): APIPromise<OpenAI.Completion>;
40
39
  };
41
40
  };
42
41
  };
@@ -1,6 +1,9 @@
1
1
  import { traceable } from "../traceable.js";
2
- function _combineChatCompletionChoices(choices) {
2
+ function _combineChatCompletionChoices(choices
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ ) {
3
5
  const reversedChoices = choices.slice().reverse();
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
7
  const message = {
5
8
  role: "assistant",
6
9
  content: "",
@@ -70,26 +73,43 @@ function _combineChatCompletionChoices(choices) {
70
73
  message: message,
71
74
  };
72
75
  }
73
- async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig) {
74
- if (args[1]?.langsmithExtra !== undefined) {
75
- const { langsmithExtra, ...openAIOptions } = args[1];
76
- const wrappedMethod = traceable(openAIMethod, {
77
- ...defaultRunConfig,
78
- ...langsmithExtra,
79
- });
80
- const finalArgs = [args[0]];
81
- if (args.length > 2) {
82
- finalArgs.push(openAIOptions);
83
- finalArgs.push(args.slice(2));
76
+ const chatAggregator = (chunks) => {
77
+ if (!chunks || chunks.length === 0) {
78
+ return { choices: [{ message: { role: "assistant", content: "" } }] };
79
+ }
80
+ const choicesByIndex = {};
81
+ for (const chunk of chunks) {
82
+ for (const choice of chunk.choices) {
83
+ if (choicesByIndex[choice.index] === undefined) {
84
+ choicesByIndex[choice.index] = [];
85
+ }
86
+ choicesByIndex[choice.index].push(choice);
84
87
  }
85
- else if (Object.keys(openAIOptions).length !== 0) {
86
- finalArgs.push(openAIOptions);
88
+ }
89
+ const aggregatedOutput = chunks[chunks.length - 1];
90
+ aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
91
+ return aggregatedOutput;
92
+ };
93
+ const textAggregator = (allChunks
94
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
+ ) => {
96
+ if (allChunks.length === 0) {
97
+ return { choices: [{ text: "" }] };
98
+ }
99
+ const allContent = [];
100
+ for (const chunk of allChunks) {
101
+ const content = chunk.choices[0].text;
102
+ if (content != null) {
103
+ allContent.push(content);
87
104
  }
88
- return wrappedMethod(...finalArgs);
89
105
  }
90
- const wrappedMethod = traceable(openAIMethod, defaultRunConfig);
91
- return wrappedMethod(...args);
92
- }
106
+ const content = allContent.join("");
107
+ const aggregatedOutput = allChunks[allChunks.length - 1];
108
+ aggregatedOutput.choices = [
109
+ { ...aggregatedOutput.choices[0], text: content },
110
+ ];
111
+ return aggregatedOutput;
112
+ };
93
113
  /**
94
114
  * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
95
115
  * tracing. Method signatures are unchanged, with the exception that you can pass
@@ -115,61 +135,20 @@ async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig
115
135
  * ```
116
136
  */
117
137
  export const wrapOpenAI = (openai, options) => {
118
- const originalChatCompletionsFn = openai.chat.completions.create.bind(openai.chat.completions);
119
- openai.chat.completions.create = async (...args) => {
120
- const aggregator = (chunks) => {
121
- if (!chunks || chunks.length === 0) {
122
- return { choices: [{ message: { role: "assistant", content: "" } }] };
123
- }
124
- const choicesByIndex = {};
125
- for (const chunk of chunks) {
126
- for (const choice of chunk.choices) {
127
- if (choicesByIndex[choice.index] === undefined) {
128
- choicesByIndex[choice.index] = [];
129
- }
130
- choicesByIndex[choice.index].push(choice);
131
- }
132
- }
133
- const aggregatedOutput = chunks[chunks.length - 1];
134
- aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
135
- return aggregatedOutput;
136
- };
137
- const defaultRunConfig = {
138
- name: "ChatOpenAI",
139
- run_type: "llm",
140
- aggregator,
141
- ...options,
142
- };
143
- return extractLangSmithExtraAndCall(originalChatCompletionsFn, args, defaultRunConfig);
144
- };
145
- const originalCompletionsFn = openai.completions.create.bind(openai.chat.completions);
146
- openai.completions.create = async (...args) => {
147
- const aggregator = (allChunks) => {
148
- if (allChunks.length === 0) {
149
- return { choices: [{ text: "" }] };
150
- }
151
- const allContent = [];
152
- for (const chunk of allChunks) {
153
- const content = chunk.choices[0].text;
154
- if (content != null) {
155
- allContent.push(content);
156
- }
157
- }
158
- const content = allContent.join("");
159
- const aggregatedOutput = allChunks[allChunks.length - 1];
160
- aggregatedOutput.choices = [
161
- { ...aggregatedOutput.choices[0], text: content },
162
- ];
163
- return aggregatedOutput;
164
- };
165
- const defaultRunConfig = {
166
- name: "OpenAI",
167
- run_type: "llm",
168
- aggregator,
169
- ...options,
170
- };
171
- return extractLangSmithExtraAndCall(originalCompletionsFn, args, defaultRunConfig);
172
- };
138
+ openai.chat.completions.create = traceable(openai.chat.completions.create.bind(openai.chat.completions), {
139
+ name: "ChatOpenAI",
140
+ run_type: "llm",
141
+ aggregator: chatAggregator,
142
+ argsConfigPath: [1, "langsmithExtra"],
143
+ ...options,
144
+ });
145
+ openai.completions.create = traceable(openai.completions.create.bind(openai.completions), {
146
+ name: "OpenAI",
147
+ run_type: "llm",
148
+ aggregator: textAggregator,
149
+ argsConfigPath: [1, "langsmithExtra"],
150
+ ...options,
151
+ });
173
152
  return openai;
174
153
  };
175
154
  const _wrapClient = (sdk, runName, options) => {
@@ -177,7 +156,7 @@ const _wrapClient = (sdk, runName, options) => {
177
156
  get(target, propKey, receiver) {
178
157
  const originalValue = target[propKey];
179
158
  if (typeof originalValue === "function") {
180
- return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
159
+ return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options));
181
160
  }
182
161
  else if (originalValue != null &&
183
162
  !Array.isArray(originalValue) &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
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": [
@@ -47,8 +47,8 @@
47
47
  "check-version": "node scripts/check-version.js",
48
48
  "check-npm-version": "node scripts/check-npm-version.js",
49
49
  "clean": "rm -rf dist/ && node scripts/create-entrypoints.js clean",
50
- "build:esm": "tsc --outDir dist/ && rm -rf dist/tests dist/**/tests",
51
- "build:cjs": "tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rm -r dist-cjs",
50
+ "build:esm": "rm -f src/package.json && tsc --outDir dist/ && rm -rf dist/tests dist/**/tests",
51
+ "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",
52
52
  "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests --testPathIgnorePatterns='\\.int\\.test.[tj]s' --testTimeout 30000",
53
53
  "test:integration": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000",
54
54
  "test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
@@ -104,7 +104,7 @@
104
104
  "prettier": "^2.8.8",
105
105
  "ts-jest": "^29.1.0",
106
106
  "ts-node": "^10.9.1",
107
- "typescript": "^5.0.4"
107
+ "typescript": "^5.4.5"
108
108
  },
109
109
  "peerDependencies": {
110
110
  "openai": "*"