langsmith 0.1.14 → 0.1.19
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/client.d.cts +1 -0
- package/dist/client.cjs +38 -4
- package/dist/client.d.ts +13 -2
- package/dist/client.js +38 -4
- package/dist/evaluation/evaluator.d.ts +44 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run_trees.cjs +9 -3
- package/dist/run_trees.d.ts +2 -1
- package/dist/run_trees.js +9 -3
- package/dist/schemas.d.ts +5 -1
- package/dist/traceable.cjs +42 -4
- package/dist/traceable.d.ts +10 -1
- package/dist/traceable.js +40 -3
- package/dist/wrappers/index.cjs +17 -0
- package/dist/wrappers/index.d.ts +1 -0
- package/dist/wrappers/index.js +1 -0
- package/dist/wrappers/openai.cjs +215 -0
- package/dist/wrappers/openai.d.ts +83 -0
- package/dist/wrappers/openai.js +210 -0
- package/evaluation.d.cts +1 -0
- package/index.d.cts +1 -0
- package/package.json +72 -16
- package/run_trees.d.cts +1 -0
- package/schemas.d.cts +1 -0
- package/traceable.d.cts +1 -0
- package/wrappers/openai.cjs +1 -0
- package/wrappers/openai.d.cts +1 -0
- package/wrappers/openai.d.ts +1 -0
- package/wrappers/openai.js +1 -0
- package/wrappers.cjs +1 -1
- package/wrappers.d.cts +1 -0
- package/wrappers.d.ts +1 -1
- package/wrappers.js +1 -1
- package/dist/wrappers.cjs +0 -54
- package/dist/wrappers.d.ts +0 -37
- package/dist/wrappers.js +0 -49
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapSDK = exports.wrapOpenAI = void 0;
|
|
4
|
+
const traceable_js_1 = require("../traceable.cjs");
|
|
5
|
+
function _combineChatCompletionChoices(choices) {
|
|
6
|
+
const reversedChoices = choices.slice().reverse();
|
|
7
|
+
const message = {
|
|
8
|
+
role: "assistant",
|
|
9
|
+
content: "",
|
|
10
|
+
};
|
|
11
|
+
for (const c of reversedChoices) {
|
|
12
|
+
if (c.delta.role) {
|
|
13
|
+
message["role"] = c.delta.role;
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const toolCalls = {};
|
|
18
|
+
for (const c of choices) {
|
|
19
|
+
if (c.delta.content) {
|
|
20
|
+
message.content = message.content.concat(c.delta.content);
|
|
21
|
+
}
|
|
22
|
+
if (c.delta.function_call) {
|
|
23
|
+
if (!message.function_call) {
|
|
24
|
+
message.function_call = { name: "", arguments: "" };
|
|
25
|
+
}
|
|
26
|
+
if (c.delta.function_call.name) {
|
|
27
|
+
message.function_call.name += c.delta.function_call.name;
|
|
28
|
+
}
|
|
29
|
+
if (c.delta.function_call.arguments) {
|
|
30
|
+
message.function_call.arguments += c.delta.function_call.arguments;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (c.delta.tool_calls) {
|
|
34
|
+
for (const tool_call of c.delta.tool_calls) {
|
|
35
|
+
if (!toolCalls[c.index]) {
|
|
36
|
+
toolCalls[c.index] = [];
|
|
37
|
+
}
|
|
38
|
+
toolCalls[c.index].push(tool_call);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (Object.keys(toolCalls).length > 0) {
|
|
43
|
+
message.tool_calls = [...Array(Object.keys(toolCalls).length)];
|
|
44
|
+
for (const [index, toolCallChunks] of Object.entries(toolCalls)) {
|
|
45
|
+
const idx = parseInt(index);
|
|
46
|
+
message.tool_calls[idx] = {
|
|
47
|
+
index: idx,
|
|
48
|
+
id: toolCallChunks.find((c) => c.id)?.id || null,
|
|
49
|
+
type: toolCallChunks.find((c) => c.type)?.type || null,
|
|
50
|
+
};
|
|
51
|
+
for (const chunk of toolCallChunks) {
|
|
52
|
+
if (chunk.function) {
|
|
53
|
+
if (!message.tool_calls[idx].function) {
|
|
54
|
+
message.tool_calls[idx].function = {
|
|
55
|
+
name: "",
|
|
56
|
+
arguments: "",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (chunk.function.name) {
|
|
60
|
+
message.tool_calls[idx].function.name += chunk.function.name;
|
|
61
|
+
}
|
|
62
|
+
if (chunk.function.arguments) {
|
|
63
|
+
message.tool_calls[idx].function.arguments +=
|
|
64
|
+
chunk.function.arguments;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
index: choices[0].index,
|
|
72
|
+
finish_reason: reversedChoices.find((c) => c.finish_reason) || null,
|
|
73
|
+
message: message,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
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));
|
|
87
|
+
}
|
|
88
|
+
else if (Object.keys(openAIOptions).length !== 0) {
|
|
89
|
+
finalArgs.push(openAIOptions);
|
|
90
|
+
}
|
|
91
|
+
return wrappedMethod(...finalArgs);
|
|
92
|
+
}
|
|
93
|
+
const wrappedMethod = (0, traceable_js_1.traceable)(openAIMethod, defaultRunConfig);
|
|
94
|
+
return wrappedMethod(...args);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Wraps an OpenAI client's completion methods, enabling automatic LangSmith
|
|
98
|
+
* tracing. Method signatures are unchanged, with the exception that you can pass
|
|
99
|
+
* an additional and optional "langsmithExtra" field within the second parameter.
|
|
100
|
+
* @param openai An OpenAI client instance.
|
|
101
|
+
* @param options LangSmith options.
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* const patchedStream = await patchedClient.chat.completions.create(
|
|
105
|
+
* {
|
|
106
|
+
* messages: [{ role: "user", content: `Say 'foo'` }],
|
|
107
|
+
* model: "gpt-3.5-turbo",
|
|
108
|
+
* stream: true,
|
|
109
|
+
* },
|
|
110
|
+
* {
|
|
111
|
+
* langsmithExtra: {
|
|
112
|
+
* metadata: {
|
|
113
|
+
* additional_data: "bar",
|
|
114
|
+
* },
|
|
115
|
+
* },
|
|
116
|
+
* },
|
|
117
|
+
* );
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
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
|
+
};
|
|
176
|
+
return openai;
|
|
177
|
+
};
|
|
178
|
+
exports.wrapOpenAI = wrapOpenAI;
|
|
179
|
+
const _wrapClient = (sdk, runName, options) => {
|
|
180
|
+
return new Proxy(sdk, {
|
|
181
|
+
get(target, propKey, receiver) {
|
|
182
|
+
const originalValue = target[propKey];
|
|
183
|
+
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));
|
|
185
|
+
}
|
|
186
|
+
else if (originalValue != null &&
|
|
187
|
+
!Array.isArray(originalValue) &&
|
|
188
|
+
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
189
|
+
!(originalValue instanceof Date) &&
|
|
190
|
+
typeof originalValue === "object") {
|
|
191
|
+
return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
return Reflect.get(target, propKey, receiver);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
|
|
201
|
+
* Method signatures are unchanged.
|
|
202
|
+
*
|
|
203
|
+
* Note that this will wrap and trace ALL SDK methods, not just
|
|
204
|
+
* LLM completion methods. If the passed SDK contains other methods,
|
|
205
|
+
* we recommend using the wrapped instance for LLM calls only.
|
|
206
|
+
* @param sdk An arbitrary SDK instance.
|
|
207
|
+
* @param options LangSmith options.
|
|
208
|
+
* @returns
|
|
209
|
+
*/
|
|
210
|
+
const wrapSDK = (sdk, options) => {
|
|
211
|
+
return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
|
|
212
|
+
client: options?.client,
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
exports.wrapSDK = wrapSDK;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { OpenAI } from "openai";
|
|
2
|
+
import type { Client, RunTreeConfig } from "../index.js";
|
|
3
|
+
import { type RunnableConfigLike } from "../run_trees.js";
|
|
4
|
+
import { type RunTreeLike } from "../traceable.js";
|
|
5
|
+
type OpenAIType = {
|
|
6
|
+
chat: {
|
|
7
|
+
completions: {
|
|
8
|
+
create: (...args: any[]) => any;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
completions: {
|
|
12
|
+
create: (...args: any[]) => any;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
type PatchedOpenAIClient<T extends OpenAIType> = {
|
|
16
|
+
[P in keyof T]: T[P];
|
|
17
|
+
} & {
|
|
18
|
+
chat: {
|
|
19
|
+
completions: {
|
|
20
|
+
create: {
|
|
21
|
+
(arg: OpenAI.ChatCompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
|
|
22
|
+
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
23
|
+
}): Promise<AsyncGenerator<OpenAI.ChatCompletionChunk>>;
|
|
24
|
+
} & {
|
|
25
|
+
(arg: OpenAI.ChatCompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
|
|
26
|
+
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
27
|
+
}): Promise<OpenAI.ChatCompletionChunk>;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
completions: {
|
|
32
|
+
create: {
|
|
33
|
+
(arg: OpenAI.CompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
|
|
34
|
+
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
35
|
+
}): Promise<AsyncGenerator<OpenAI.Completion>>;
|
|
36
|
+
} & {
|
|
37
|
+
(arg: OpenAI.CompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
|
|
38
|
+
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
39
|
+
}): Promise<OpenAI.Completion>;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Wraps an OpenAI client's completion methods, enabling automatic LangSmith
|
|
45
|
+
* tracing. Method signatures are unchanged, with the exception that you can pass
|
|
46
|
+
* an additional and optional "langsmithExtra" field within the second parameter.
|
|
47
|
+
* @param openai An OpenAI client instance.
|
|
48
|
+
* @param options LangSmith options.
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const patchedStream = await patchedClient.chat.completions.create(
|
|
52
|
+
* {
|
|
53
|
+
* messages: [{ role: "user", content: `Say 'foo'` }],
|
|
54
|
+
* model: "gpt-3.5-turbo",
|
|
55
|
+
* stream: true,
|
|
56
|
+
* },
|
|
57
|
+
* {
|
|
58
|
+
* langsmithExtra: {
|
|
59
|
+
* metadata: {
|
|
60
|
+
* additional_data: "bar",
|
|
61
|
+
* },
|
|
62
|
+
* },
|
|
63
|
+
* },
|
|
64
|
+
* );
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare const wrapOpenAI: <T extends OpenAIType>(openai: T, options?: Partial<RunTreeConfig>) => PatchedOpenAIClient<T>;
|
|
68
|
+
/**
|
|
69
|
+
* Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
|
|
70
|
+
* Method signatures are unchanged.
|
|
71
|
+
*
|
|
72
|
+
* Note that this will wrap and trace ALL SDK methods, not just
|
|
73
|
+
* LLM completion methods. If the passed SDK contains other methods,
|
|
74
|
+
* we recommend using the wrapped instance for LLM calls only.
|
|
75
|
+
* @param sdk An arbitrary SDK instance.
|
|
76
|
+
* @param options LangSmith options.
|
|
77
|
+
* @returns
|
|
78
|
+
*/
|
|
79
|
+
export declare const wrapSDK: <T extends object>(sdk: T, options?: {
|
|
80
|
+
client?: Client;
|
|
81
|
+
runName?: string;
|
|
82
|
+
}) => T;
|
|
83
|
+
export {};
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { traceable } from "../traceable.js";
|
|
2
|
+
function _combineChatCompletionChoices(choices) {
|
|
3
|
+
const reversedChoices = choices.slice().reverse();
|
|
4
|
+
const message = {
|
|
5
|
+
role: "assistant",
|
|
6
|
+
content: "",
|
|
7
|
+
};
|
|
8
|
+
for (const c of reversedChoices) {
|
|
9
|
+
if (c.delta.role) {
|
|
10
|
+
message["role"] = c.delta.role;
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const toolCalls = {};
|
|
15
|
+
for (const c of choices) {
|
|
16
|
+
if (c.delta.content) {
|
|
17
|
+
message.content = message.content.concat(c.delta.content);
|
|
18
|
+
}
|
|
19
|
+
if (c.delta.function_call) {
|
|
20
|
+
if (!message.function_call) {
|
|
21
|
+
message.function_call = { name: "", arguments: "" };
|
|
22
|
+
}
|
|
23
|
+
if (c.delta.function_call.name) {
|
|
24
|
+
message.function_call.name += c.delta.function_call.name;
|
|
25
|
+
}
|
|
26
|
+
if (c.delta.function_call.arguments) {
|
|
27
|
+
message.function_call.arguments += c.delta.function_call.arguments;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (c.delta.tool_calls) {
|
|
31
|
+
for (const tool_call of c.delta.tool_calls) {
|
|
32
|
+
if (!toolCalls[c.index]) {
|
|
33
|
+
toolCalls[c.index] = [];
|
|
34
|
+
}
|
|
35
|
+
toolCalls[c.index].push(tool_call);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (Object.keys(toolCalls).length > 0) {
|
|
40
|
+
message.tool_calls = [...Array(Object.keys(toolCalls).length)];
|
|
41
|
+
for (const [index, toolCallChunks] of Object.entries(toolCalls)) {
|
|
42
|
+
const idx = parseInt(index);
|
|
43
|
+
message.tool_calls[idx] = {
|
|
44
|
+
index: idx,
|
|
45
|
+
id: toolCallChunks.find((c) => c.id)?.id || null,
|
|
46
|
+
type: toolCallChunks.find((c) => c.type)?.type || null,
|
|
47
|
+
};
|
|
48
|
+
for (const chunk of toolCallChunks) {
|
|
49
|
+
if (chunk.function) {
|
|
50
|
+
if (!message.tool_calls[idx].function) {
|
|
51
|
+
message.tool_calls[idx].function = {
|
|
52
|
+
name: "",
|
|
53
|
+
arguments: "",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (chunk.function.name) {
|
|
57
|
+
message.tool_calls[idx].function.name += chunk.function.name;
|
|
58
|
+
}
|
|
59
|
+
if (chunk.function.arguments) {
|
|
60
|
+
message.tool_calls[idx].function.arguments +=
|
|
61
|
+
chunk.function.arguments;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
index: choices[0].index,
|
|
69
|
+
finish_reason: reversedChoices.find((c) => c.finish_reason) || null,
|
|
70
|
+
message: message,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
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));
|
|
84
|
+
}
|
|
85
|
+
else if (Object.keys(openAIOptions).length !== 0) {
|
|
86
|
+
finalArgs.push(openAIOptions);
|
|
87
|
+
}
|
|
88
|
+
return wrappedMethod(...finalArgs);
|
|
89
|
+
}
|
|
90
|
+
const wrappedMethod = traceable(openAIMethod, defaultRunConfig);
|
|
91
|
+
return wrappedMethod(...args);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Wraps an OpenAI client's completion methods, enabling automatic LangSmith
|
|
95
|
+
* tracing. Method signatures are unchanged, with the exception that you can pass
|
|
96
|
+
* an additional and optional "langsmithExtra" field within the second parameter.
|
|
97
|
+
* @param openai An OpenAI client instance.
|
|
98
|
+
* @param options LangSmith options.
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* const patchedStream = await patchedClient.chat.completions.create(
|
|
102
|
+
* {
|
|
103
|
+
* messages: [{ role: "user", content: `Say 'foo'` }],
|
|
104
|
+
* model: "gpt-3.5-turbo",
|
|
105
|
+
* stream: true,
|
|
106
|
+
* },
|
|
107
|
+
* {
|
|
108
|
+
* langsmithExtra: {
|
|
109
|
+
* metadata: {
|
|
110
|
+
* additional_data: "bar",
|
|
111
|
+
* },
|
|
112
|
+
* },
|
|
113
|
+
* },
|
|
114
|
+
* );
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
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
|
+
};
|
|
173
|
+
return openai;
|
|
174
|
+
};
|
|
175
|
+
const _wrapClient = (sdk, runName, options) => {
|
|
176
|
+
return new Proxy(sdk, {
|
|
177
|
+
get(target, propKey, receiver) {
|
|
178
|
+
const originalValue = target[propKey];
|
|
179
|
+
if (typeof originalValue === "function") {
|
|
180
|
+
return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
|
|
181
|
+
}
|
|
182
|
+
else if (originalValue != null &&
|
|
183
|
+
!Array.isArray(originalValue) &&
|
|
184
|
+
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
185
|
+
!(originalValue instanceof Date) &&
|
|
186
|
+
typeof originalValue === "object") {
|
|
187
|
+
return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
return Reflect.get(target, propKey, receiver);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
|
|
197
|
+
* Method signatures are unchanged.
|
|
198
|
+
*
|
|
199
|
+
* Note that this will wrap and trace ALL SDK methods, not just
|
|
200
|
+
* LLM completion methods. If the passed SDK contains other methods,
|
|
201
|
+
* we recommend using the wrapped instance for LLM calls only.
|
|
202
|
+
* @param sdk An arbitrary SDK instance.
|
|
203
|
+
* @param options LangSmith options.
|
|
204
|
+
* @returns
|
|
205
|
+
*/
|
|
206
|
+
export const wrapSDK = (sdk, options) => {
|
|
207
|
+
return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
|
|
208
|
+
client: options?.client,
|
|
209
|
+
});
|
|
210
|
+
};
|
package/evaluation.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/evaluation/index.js'
|
package/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/index.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "langsmith",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
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": [
|
|
@@ -8,24 +8,35 @@
|
|
|
8
8
|
"client.cjs",
|
|
9
9
|
"client.js",
|
|
10
10
|
"client.d.ts",
|
|
11
|
+
"client.d.cts",
|
|
11
12
|
"run_trees.cjs",
|
|
12
13
|
"run_trees.js",
|
|
13
14
|
"run_trees.d.ts",
|
|
15
|
+
"run_trees.d.cts",
|
|
14
16
|
"traceable.cjs",
|
|
15
17
|
"traceable.js",
|
|
16
18
|
"traceable.d.ts",
|
|
19
|
+
"traceable.d.cts",
|
|
17
20
|
"evaluation.cjs",
|
|
18
21
|
"evaluation.js",
|
|
19
22
|
"evaluation.d.ts",
|
|
23
|
+
"evaluation.d.cts",
|
|
20
24
|
"schemas.cjs",
|
|
21
25
|
"schemas.js",
|
|
22
26
|
"schemas.d.ts",
|
|
27
|
+
"schemas.d.cts",
|
|
23
28
|
"wrappers.cjs",
|
|
24
29
|
"wrappers.js",
|
|
25
30
|
"wrappers.d.ts",
|
|
31
|
+
"wrappers.d.cts",
|
|
32
|
+
"wrappers/openai.cjs",
|
|
33
|
+
"wrappers/openai.js",
|
|
34
|
+
"wrappers/openai.d.ts",
|
|
35
|
+
"wrappers/openai.d.cts",
|
|
26
36
|
"index.cjs",
|
|
27
37
|
"index.js",
|
|
28
|
-
"index.d.ts"
|
|
38
|
+
"index.d.ts",
|
|
39
|
+
"index.d.cts"
|
|
29
40
|
],
|
|
30
41
|
"type": "module",
|
|
31
42
|
"main": "./dist/index.js",
|
|
@@ -63,6 +74,13 @@
|
|
|
63
74
|
"url": "https://github.com/langchain-ai/langsmith-sdk/issues"
|
|
64
75
|
},
|
|
65
76
|
"homepage": "https://github.com/langchain-ai/langsmith-sdk#readme",
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"@types/uuid": "^9.0.1",
|
|
79
|
+
"commander": "^10.0.1",
|
|
80
|
+
"p-queue": "^6.6.2",
|
|
81
|
+
"p-retry": "4",
|
|
82
|
+
"uuid": "^9.0.0"
|
|
83
|
+
},
|
|
66
84
|
"devDependencies": {
|
|
67
85
|
"@babel/preset-env": "^7.22.4",
|
|
68
86
|
"@jest/globals": "^29.5.0",
|
|
@@ -81,18 +99,19 @@
|
|
|
81
99
|
"eslint-plugin-no-instanceof": "^1.0.1",
|
|
82
100
|
"eslint-plugin-prettier": "^4.2.1",
|
|
83
101
|
"jest": "^29.5.0",
|
|
84
|
-
"openai": "^4.
|
|
102
|
+
"openai": "^4.38.5",
|
|
85
103
|
"prettier": "^2.8.8",
|
|
86
104
|
"ts-jest": "^29.1.0",
|
|
87
105
|
"ts-node": "^10.9.1",
|
|
88
106
|
"typescript": "^5.0.4"
|
|
89
107
|
},
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"
|
|
95
|
-
|
|
108
|
+
"peerDependencies": {
|
|
109
|
+
"openai": "*"
|
|
110
|
+
},
|
|
111
|
+
"peerDependenciesMeta": {
|
|
112
|
+
"openai": {
|
|
113
|
+
"optional": true
|
|
114
|
+
}
|
|
96
115
|
},
|
|
97
116
|
"lint-staged": {
|
|
98
117
|
"**/*.{ts,tsx}": [
|
|
@@ -102,40 +121,77 @@
|
|
|
102
121
|
},
|
|
103
122
|
"exports": {
|
|
104
123
|
".": {
|
|
105
|
-
"types":
|
|
124
|
+
"types": {
|
|
125
|
+
"import": "./index.d.ts",
|
|
126
|
+
"require": "./index.d.cts",
|
|
127
|
+
"default": "./index.d.ts"
|
|
128
|
+
},
|
|
106
129
|
"import": "./index.js",
|
|
107
130
|
"require": "./index.cjs"
|
|
108
131
|
},
|
|
109
132
|
"./client": {
|
|
110
|
-
"types":
|
|
133
|
+
"types": {
|
|
134
|
+
"import": "./client.d.ts",
|
|
135
|
+
"require": "./client.d.cts",
|
|
136
|
+
"default": "./client.d.ts"
|
|
137
|
+
},
|
|
111
138
|
"import": "./client.js",
|
|
112
139
|
"require": "./client.cjs"
|
|
113
140
|
},
|
|
114
141
|
"./run_trees": {
|
|
115
|
-
"types":
|
|
142
|
+
"types": {
|
|
143
|
+
"import": "./run_trees.d.ts",
|
|
144
|
+
"require": "./run_trees.d.cts",
|
|
145
|
+
"default": "./run_trees.d.ts"
|
|
146
|
+
},
|
|
116
147
|
"import": "./run_trees.js",
|
|
117
148
|
"require": "./run_trees.cjs"
|
|
118
149
|
},
|
|
119
150
|
"./traceable": {
|
|
120
|
-
"types":
|
|
151
|
+
"types": {
|
|
152
|
+
"import": "./traceable.d.ts",
|
|
153
|
+
"require": "./traceable.d.cts",
|
|
154
|
+
"default": "./traceable.d.ts"
|
|
155
|
+
},
|
|
121
156
|
"import": "./traceable.js",
|
|
122
157
|
"require": "./traceable.cjs"
|
|
123
158
|
},
|
|
124
159
|
"./evaluation": {
|
|
125
|
-
"types":
|
|
160
|
+
"types": {
|
|
161
|
+
"import": "./evaluation.d.ts",
|
|
162
|
+
"require": "./evaluation.d.cts",
|
|
163
|
+
"default": "./evaluation.d.ts"
|
|
164
|
+
},
|
|
126
165
|
"import": "./evaluation.js",
|
|
127
166
|
"require": "./evaluation.cjs"
|
|
128
167
|
},
|
|
129
168
|
"./schemas": {
|
|
130
|
-
"types":
|
|
169
|
+
"types": {
|
|
170
|
+
"import": "./schemas.d.ts",
|
|
171
|
+
"require": "./schemas.d.cts",
|
|
172
|
+
"default": "./schemas.d.ts"
|
|
173
|
+
},
|
|
131
174
|
"import": "./schemas.js",
|
|
132
175
|
"require": "./schemas.cjs"
|
|
133
176
|
},
|
|
134
177
|
"./wrappers": {
|
|
135
|
-
"types":
|
|
178
|
+
"types": {
|
|
179
|
+
"import": "./wrappers.d.ts",
|
|
180
|
+
"require": "./wrappers.d.cts",
|
|
181
|
+
"default": "./wrappers.d.ts"
|
|
182
|
+
},
|
|
136
183
|
"import": "./wrappers.js",
|
|
137
184
|
"require": "./wrappers.cjs"
|
|
138
185
|
},
|
|
186
|
+
"./wrappers/openai": {
|
|
187
|
+
"types": {
|
|
188
|
+
"import": "./wrappers/openai.d.ts",
|
|
189
|
+
"require": "./wrappers/openai.d.cts",
|
|
190
|
+
"default": "./wrappers/openai.d.ts"
|
|
191
|
+
},
|
|
192
|
+
"import": "./wrappers/openai.js",
|
|
193
|
+
"require": "./wrappers/openai.cjs"
|
|
194
|
+
},
|
|
139
195
|
"./package.json": "./package.json"
|
|
140
196
|
}
|
|
141
197
|
}
|
package/run_trees.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/run_trees.js'
|
package/schemas.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/schemas.js'
|
package/traceable.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/traceable.js'
|