@langchain/openai 0.0.27 → 0.0.28
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/dist/chat_models.cjs
CHANGED
|
@@ -48,12 +48,30 @@ function messageToOpenAIRole(message) {
|
|
|
48
48
|
}
|
|
49
49
|
exports.messageToOpenAIRole = messageToOpenAIRole;
|
|
50
50
|
function openAIResponseToChatMessage(message) {
|
|
51
|
+
const rawToolCalls = message.tool_calls;
|
|
51
52
|
switch (message.role) {
|
|
52
|
-
case "assistant":
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
case "assistant": {
|
|
54
|
+
const toolCalls = [];
|
|
55
|
+
const invalidToolCalls = [];
|
|
56
|
+
for (const rawToolCall of rawToolCalls ?? []) {
|
|
57
|
+
try {
|
|
58
|
+
toolCalls.push((0, openai_tools_1.parseToolCall)(rawToolCall, { returnId: true }));
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
invalidToolCalls.push((0, openai_tools_1.makeInvalidToolCall)(rawToolCall, e.message));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return new messages_1.AIMessage({
|
|
66
|
+
content: message.content || "",
|
|
67
|
+
tool_calls: toolCalls,
|
|
68
|
+
invalid_tool_calls: invalidToolCalls,
|
|
69
|
+
additional_kwargs: {
|
|
70
|
+
function_call: message.function_call,
|
|
71
|
+
tool_calls: rawToolCalls,
|
|
72
|
+
},
|
|
56
73
|
});
|
|
74
|
+
}
|
|
57
75
|
default:
|
|
58
76
|
return new messages_1.ChatMessage(message.content || "", message.role ?? "unknown");
|
|
59
77
|
}
|
|
@@ -81,7 +99,22 @@ delta, defaultRole) {
|
|
|
81
99
|
return new messages_1.HumanMessageChunk({ content });
|
|
82
100
|
}
|
|
83
101
|
else if (role === "assistant") {
|
|
84
|
-
|
|
102
|
+
const toolCallChunks = [];
|
|
103
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
104
|
+
for (const rawToolCall of delta.tool_calls) {
|
|
105
|
+
toolCallChunks.push({
|
|
106
|
+
name: rawToolCall.function?.name,
|
|
107
|
+
args: rawToolCall.function?.arguments,
|
|
108
|
+
id: rawToolCall.id,
|
|
109
|
+
index: rawToolCall.index,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return new messages_1.AIMessageChunk({
|
|
114
|
+
content,
|
|
115
|
+
tool_call_chunks: toolCallChunks,
|
|
116
|
+
additional_kwargs,
|
|
117
|
+
});
|
|
85
118
|
}
|
|
86
119
|
else if (role === "system") {
|
|
87
120
|
return new messages_1.SystemMessageChunk({ content });
|
|
@@ -118,11 +151,16 @@ function convertMessagesToOpenAIParams(messages) {
|
|
|
118
151
|
if (message.additional_kwargs.function_call != null) {
|
|
119
152
|
completionParam.function_call = message.additional_kwargs.function_call;
|
|
120
153
|
}
|
|
121
|
-
if (message.
|
|
122
|
-
completionParam.tool_calls = message.
|
|
154
|
+
if ((0, messages_1.isAIMessage)(message) && !!message.tool_calls?.length) {
|
|
155
|
+
completionParam.tool_calls = message.tool_calls.map(openai_tools_1.convertLangChainToolCallToOpenAI);
|
|
123
156
|
}
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
else {
|
|
158
|
+
if (message.additional_kwargs.tool_calls != null) {
|
|
159
|
+
completionParam.tool_calls = message.additional_kwargs.tool_calls;
|
|
160
|
+
}
|
|
161
|
+
if (message.tool_call_id != null) {
|
|
162
|
+
completionParam.tool_call_id = message.tool_call_id;
|
|
163
|
+
}
|
|
126
164
|
}
|
|
127
165
|
return completionParam;
|
|
128
166
|
});
|
|
@@ -437,6 +475,12 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
437
475
|
...fields?.configuration,
|
|
438
476
|
};
|
|
439
477
|
}
|
|
478
|
+
bindTools(tools, kwargs) {
|
|
479
|
+
return this.bind({
|
|
480
|
+
tools: tools.map(function_calling_1.convertToOpenAITool),
|
|
481
|
+
...kwargs,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
440
484
|
/**
|
|
441
485
|
* Get the parameters used to invoke the model
|
|
442
486
|
*/
|
package/dist/chat_models.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
|
|
2
2
|
import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
|
|
3
|
-
import { type BaseMessage } from "@langchain/core/messages";
|
|
3
|
+
import { AIMessageChunk, type BaseMessage } from "@langchain/core/messages";
|
|
4
4
|
import { ChatGenerationChunk, type ChatResult } from "@langchain/core/outputs";
|
|
5
5
|
import { type StructuredToolInterface } from "@langchain/core/tools";
|
|
6
6
|
import { BaseChatModel, type BaseChatModelParams } from "@langchain/core/language_models/chat_models";
|
|
7
7
|
import type { BaseFunctionCallOptions, BaseLanguageModelInput, StructuredOutputMethodOptions, StructuredOutputMethodParams } from "@langchain/core/language_models/base";
|
|
8
8
|
import { z } from "zod";
|
|
9
|
-
import { Runnable } from "@langchain/core/runnables";
|
|
9
|
+
import { Runnable, RunnableInterface } from "@langchain/core/runnables";
|
|
10
10
|
import type { AzureOpenAIInput, OpenAICallOptions, OpenAIChatInput, OpenAICoreRequestOptions, LegacyOpenAIInput } from "./types.js";
|
|
11
11
|
export type { AzureOpenAIInput, OpenAICallOptions, OpenAIChatInput };
|
|
12
12
|
interface TokenUsage {
|
|
@@ -62,7 +62,7 @@ export interface ChatOpenAICallOptions extends OpenAICallOptions, BaseFunctionCa
|
|
|
62
62
|
*
|
|
63
63
|
* ```
|
|
64
64
|
*/
|
|
65
|
-
export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = ChatOpenAICallOptions> extends BaseChatModel<CallOptions> implements OpenAIChatInput, AzureOpenAIInput {
|
|
65
|
+
export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = ChatOpenAICallOptions> extends BaseChatModel<CallOptions, AIMessageChunk> implements OpenAIChatInput, AzureOpenAIInput {
|
|
66
66
|
static lc_name(): string;
|
|
67
67
|
get callKeys(): string[];
|
|
68
68
|
lc_serializable: boolean;
|
|
@@ -102,6 +102,7 @@ export declare class ChatOpenAI<CallOptions extends ChatOpenAICallOptions = Chat
|
|
|
102
102
|
},
|
|
103
103
|
/** @deprecated */
|
|
104
104
|
configuration?: ClientOptions & LegacyOpenAIInput);
|
|
105
|
+
bindTools(tools: (Record<string, unknown> | StructuredToolInterface)[], kwargs?: Partial<CallOptions>): RunnableInterface<BaseLanguageModelInput, AIMessageChunk, CallOptions>;
|
|
105
106
|
/**
|
|
106
107
|
* Get the parameters used to invoke the model
|
|
107
108
|
*/
|
package/dist/chat_models.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { OpenAI as OpenAIClient } from "openai";
|
|
2
|
-
import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, } from "@langchain/core/messages";
|
|
2
|
+
import { AIMessage, AIMessageChunk, ChatMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, SystemMessageChunk, ToolMessageChunk, isAIMessage, } from "@langchain/core/messages";
|
|
3
3
|
import { ChatGenerationChunk, } from "@langchain/core/outputs";
|
|
4
4
|
import { getEnvironmentVariable } from "@langchain/core/utils/env";
|
|
5
5
|
import { BaseChatModel, } from "@langchain/core/language_models/chat_models";
|
|
6
6
|
import { convertToOpenAITool } from "@langchain/core/utils/function_calling";
|
|
7
7
|
import { RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnables";
|
|
8
8
|
import { JsonOutputParser, StructuredOutputParser, } from "@langchain/core/output_parsers";
|
|
9
|
-
import { JsonOutputKeyToolsParser } from "@langchain/core/output_parsers/openai_tools";
|
|
9
|
+
import { JsonOutputKeyToolsParser, convertLangChainToolCallToOpenAI, makeInvalidToolCall, parseToolCall, } from "@langchain/core/output_parsers/openai_tools";
|
|
10
10
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
11
11
|
import { getEndpoint } from "./utils/azure.js";
|
|
12
12
|
import { wrapOpenAIClientError } from "./utils/openai.js";
|
|
@@ -44,12 +44,30 @@ export function messageToOpenAIRole(message) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
function openAIResponseToChatMessage(message) {
|
|
47
|
+
const rawToolCalls = message.tool_calls;
|
|
47
48
|
switch (message.role) {
|
|
48
|
-
case "assistant":
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
case "assistant": {
|
|
50
|
+
const toolCalls = [];
|
|
51
|
+
const invalidToolCalls = [];
|
|
52
|
+
for (const rawToolCall of rawToolCalls ?? []) {
|
|
53
|
+
try {
|
|
54
|
+
toolCalls.push(parseToolCall(rawToolCall, { returnId: true }));
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
invalidToolCalls.push(makeInvalidToolCall(rawToolCall, e.message));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return new AIMessage({
|
|
62
|
+
content: message.content || "",
|
|
63
|
+
tool_calls: toolCalls,
|
|
64
|
+
invalid_tool_calls: invalidToolCalls,
|
|
65
|
+
additional_kwargs: {
|
|
66
|
+
function_call: message.function_call,
|
|
67
|
+
tool_calls: rawToolCalls,
|
|
68
|
+
},
|
|
52
69
|
});
|
|
70
|
+
}
|
|
53
71
|
default:
|
|
54
72
|
return new ChatMessage(message.content || "", message.role ?? "unknown");
|
|
55
73
|
}
|
|
@@ -77,7 +95,22 @@ delta, defaultRole) {
|
|
|
77
95
|
return new HumanMessageChunk({ content });
|
|
78
96
|
}
|
|
79
97
|
else if (role === "assistant") {
|
|
80
|
-
|
|
98
|
+
const toolCallChunks = [];
|
|
99
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
100
|
+
for (const rawToolCall of delta.tool_calls) {
|
|
101
|
+
toolCallChunks.push({
|
|
102
|
+
name: rawToolCall.function?.name,
|
|
103
|
+
args: rawToolCall.function?.arguments,
|
|
104
|
+
id: rawToolCall.id,
|
|
105
|
+
index: rawToolCall.index,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return new AIMessageChunk({
|
|
110
|
+
content,
|
|
111
|
+
tool_call_chunks: toolCallChunks,
|
|
112
|
+
additional_kwargs,
|
|
113
|
+
});
|
|
81
114
|
}
|
|
82
115
|
else if (role === "system") {
|
|
83
116
|
return new SystemMessageChunk({ content });
|
|
@@ -114,11 +147,16 @@ function convertMessagesToOpenAIParams(messages) {
|
|
|
114
147
|
if (message.additional_kwargs.function_call != null) {
|
|
115
148
|
completionParam.function_call = message.additional_kwargs.function_call;
|
|
116
149
|
}
|
|
117
|
-
if (message.
|
|
118
|
-
completionParam.tool_calls = message.
|
|
150
|
+
if (isAIMessage(message) && !!message.tool_calls?.length) {
|
|
151
|
+
completionParam.tool_calls = message.tool_calls.map(convertLangChainToolCallToOpenAI);
|
|
119
152
|
}
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
else {
|
|
154
|
+
if (message.additional_kwargs.tool_calls != null) {
|
|
155
|
+
completionParam.tool_calls = message.additional_kwargs.tool_calls;
|
|
156
|
+
}
|
|
157
|
+
if (message.tool_call_id != null) {
|
|
158
|
+
completionParam.tool_call_id = message.tool_call_id;
|
|
159
|
+
}
|
|
122
160
|
}
|
|
123
161
|
return completionParam;
|
|
124
162
|
});
|
|
@@ -433,6 +471,12 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
433
471
|
...fields?.configuration,
|
|
434
472
|
};
|
|
435
473
|
}
|
|
474
|
+
bindTools(tools, kwargs) {
|
|
475
|
+
return this.bind({
|
|
476
|
+
tools: tools.map(convertToOpenAITool),
|
|
477
|
+
...kwargs,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
436
480
|
/**
|
|
437
481
|
* Get the parameters used to invoke the model
|
|
438
482
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { test, expect, jest } from "@jest/globals";
|
|
2
|
-
import { HumanMessage, ToolMessage } from "@langchain/core/messages";
|
|
2
|
+
import { AIMessage, HumanMessage, ToolMessage } from "@langchain/core/messages";
|
|
3
3
|
import { InMemoryCache } from "@langchain/core/caches";
|
|
4
4
|
import { ChatOpenAI } from "../chat_models.js";
|
|
5
5
|
test("Test ChatOpenAI JSON mode", async () => {
|
|
@@ -60,7 +60,10 @@ test("Test ChatOpenAI tool calling", async () => {
|
|
|
60
60
|
["human", "What's the weather like in San Francisco, Tokyo, and Paris?"],
|
|
61
61
|
]);
|
|
62
62
|
console.log(JSON.stringify(res));
|
|
63
|
-
expect(res.additional_kwargs.tool_calls?.length).
|
|
63
|
+
expect(res.additional_kwargs.tool_calls?.length).toEqual(3);
|
|
64
|
+
expect(res.tool_calls?.[0].args).toEqual(JSON.parse(res.additional_kwargs.tool_calls?.[0].function.arguments ?? "{}"));
|
|
65
|
+
expect(res.tool_calls?.[1].args).toEqual(JSON.parse(res.additional_kwargs.tool_calls?.[1].function.arguments ?? "{}"));
|
|
66
|
+
expect(res.tool_calls?.[2].args).toEqual(JSON.parse(res.additional_kwargs.tool_calls?.[2].function.arguments ?? "{}"));
|
|
64
67
|
});
|
|
65
68
|
test("Test ChatOpenAI streaming logprobs", async () => {
|
|
66
69
|
const model = new ChatOpenAI({
|
|
@@ -203,3 +206,54 @@ test("ChatOpenAI in JSON mode can cache generations", async () => {
|
|
|
203
206
|
lookupSpy.mockRestore();
|
|
204
207
|
updateSpy.mockRestore();
|
|
205
208
|
});
|
|
209
|
+
test("Few shotting with tool calls", async () => {
|
|
210
|
+
const chat = new ChatOpenAI({
|
|
211
|
+
modelName: "gpt-3.5-turbo-1106",
|
|
212
|
+
temperature: 1,
|
|
213
|
+
}).bind({
|
|
214
|
+
tools: [
|
|
215
|
+
{
|
|
216
|
+
type: "function",
|
|
217
|
+
function: {
|
|
218
|
+
name: "get_current_weather",
|
|
219
|
+
description: "Get the current weather in a given location",
|
|
220
|
+
parameters: {
|
|
221
|
+
type: "object",
|
|
222
|
+
properties: {
|
|
223
|
+
location: {
|
|
224
|
+
type: "string",
|
|
225
|
+
description: "The city and state, e.g. San Francisco, CA",
|
|
226
|
+
},
|
|
227
|
+
unit: { type: "string", enum: ["celsius", "fahrenheit"] },
|
|
228
|
+
},
|
|
229
|
+
required: ["location"],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
tool_choice: "auto",
|
|
235
|
+
});
|
|
236
|
+
const res = await chat.invoke([
|
|
237
|
+
new HumanMessage("What is the weather in SF?"),
|
|
238
|
+
new AIMessage({
|
|
239
|
+
content: "",
|
|
240
|
+
tool_calls: [
|
|
241
|
+
{
|
|
242
|
+
id: "12345",
|
|
243
|
+
name: "get_current_weather",
|
|
244
|
+
args: {
|
|
245
|
+
location: "SF",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
}),
|
|
250
|
+
new ToolMessage({
|
|
251
|
+
tool_call_id: "12345",
|
|
252
|
+
content: "It is currently 24 degrees with hail in SF.",
|
|
253
|
+
}),
|
|
254
|
+
new AIMessage("It is currently 24 degrees in SF with hail in SF."),
|
|
255
|
+
new HumanMessage("What did you say the weather was?"),
|
|
256
|
+
]);
|
|
257
|
+
console.log(res);
|
|
258
|
+
expect(res.content).toContain("24");
|
|
259
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/openai",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.28",
|
|
4
4
|
"description": "OpenAI integrations for LangChain.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"author": "LangChain",
|
|
40
40
|
"license": "MIT",
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@langchain/core": "~0.1.
|
|
42
|
+
"@langchain/core": "~0.1.56",
|
|
43
43
|
"js-tiktoken": "^1.0.7",
|
|
44
44
|
"openai": "^4.32.1",
|
|
45
45
|
"zod": "^3.22.4",
|