@langchain/openai 0.0.18 → 0.0.20
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 +26 -6
- package/dist/chat_models.js +27 -7
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/legacy.cjs +1 -1
- package/dist/legacy.d.ts +1 -1
- package/dist/legacy.js +1 -1
- package/dist/llms.cjs +1 -1
- package/dist/llms.d.ts +1 -1
- package/dist/llms.js +1 -1
- package/dist/tests/chat_models-extended.int.test.js +11 -0
- package/dist/tests/chat_models.int.test.js +15 -193
- package/dist/tests/chat_models_structured_output.int.test.d.ts +1 -0
- package/dist/tests/chat_models_structured_output.int.test.js +168 -0
- package/dist/tests/embeddings.int.test.js +1 -0
- package/dist/tests/legacy.int.test.js +8 -8
- package/dist/tests/llms.int.test.js +16 -13
- package/dist/tools/dalle.cjs +124 -0
- package/dist/tools/dalle.d.ts +79 -0
- package/dist/tools/dalle.js +120 -0
- package/dist/tools/index.cjs +17 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/tests/dalle.int.test.d.ts +1 -0
- package/dist/tools/tests/dalle.int.test.js +16 -0
- package/package.json +2 -2
package/dist/chat_models.cjs
CHANGED
|
@@ -470,10 +470,18 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
470
470
|
console.log("[WARNING]: Received non-string content from OpenAI. This is currently not supported.");
|
|
471
471
|
continue;
|
|
472
472
|
}
|
|
473
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
474
|
+
const generationInfo = { ...newTokenIndices };
|
|
475
|
+
if (choice.finish_reason !== undefined) {
|
|
476
|
+
generationInfo.finish_reason = choice.finish_reason;
|
|
477
|
+
}
|
|
478
|
+
if (this.logprobs) {
|
|
479
|
+
generationInfo.logprobs = choice.logprobs;
|
|
480
|
+
}
|
|
473
481
|
const generationChunk = new outputs_1.ChatGenerationChunk({
|
|
474
482
|
message: chunk,
|
|
475
483
|
text: chunk.content,
|
|
476
|
-
generationInfo
|
|
484
|
+
generationInfo,
|
|
477
485
|
});
|
|
478
486
|
yield generationChunk;
|
|
479
487
|
// eslint-disable-next-line no-void
|
|
@@ -499,6 +507,10 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
499
507
|
const stream = this._streamResponseChunks(messages, options, runManager);
|
|
500
508
|
const finalChunks = {};
|
|
501
509
|
for await (const chunk of stream) {
|
|
510
|
+
chunk.message.response_metadata = {
|
|
511
|
+
...chunk.generationInfo,
|
|
512
|
+
...chunk.message.response_metadata,
|
|
513
|
+
};
|
|
502
514
|
const index = chunk.generationInfo?.completion ?? 0;
|
|
503
515
|
if (finalChunks[index] === undefined) {
|
|
504
516
|
finalChunks[index] = chunk;
|
|
@@ -742,21 +754,26 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
742
754
|
llm = this.bind({
|
|
743
755
|
response_format: { type: "json_object" },
|
|
744
756
|
});
|
|
745
|
-
|
|
757
|
+
if (isZodSchema(schema)) {
|
|
758
|
+
outputParser = output_parsers_1.StructuredOutputParser.fromZodSchema(schema);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
outputParser = new output_parsers_1.JsonOutputParser();
|
|
762
|
+
}
|
|
746
763
|
}
|
|
747
764
|
else {
|
|
748
765
|
const functionName = name ?? "extract";
|
|
749
766
|
// Is function calling
|
|
750
767
|
if (isZodSchema(schema)) {
|
|
751
|
-
const
|
|
768
|
+
const asJsonSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(schema);
|
|
752
769
|
llm = this.bind({
|
|
753
770
|
tools: [
|
|
754
771
|
{
|
|
755
772
|
type: "function",
|
|
756
773
|
function: {
|
|
757
774
|
name: functionName,
|
|
758
|
-
description:
|
|
759
|
-
parameters:
|
|
775
|
+
description: asJsonSchema.description,
|
|
776
|
+
parameters: asJsonSchema,
|
|
760
777
|
},
|
|
761
778
|
},
|
|
762
779
|
],
|
|
@@ -770,6 +787,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
770
787
|
outputParser = new openai_tools_1.JsonOutputKeyToolsParser({
|
|
771
788
|
returnSingle: true,
|
|
772
789
|
keyName: functionName,
|
|
790
|
+
zodSchema: schema,
|
|
773
791
|
});
|
|
774
792
|
}
|
|
775
793
|
else {
|
|
@@ -819,7 +837,9 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
|
|
|
819
837
|
}
|
|
820
838
|
}
|
|
821
839
|
exports.ChatOpenAI = ChatOpenAI;
|
|
822
|
-
function isZodSchema(
|
|
840
|
+
function isZodSchema(
|
|
841
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
842
|
+
input) {
|
|
823
843
|
// Check for a characteristic method of Zod schemas
|
|
824
844
|
return typeof input?.parse === "function";
|
|
825
845
|
}
|
package/dist/chat_models.js
CHANGED
|
@@ -5,7 +5,7 @@ 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
|
-
import { JsonOutputParser } from "@langchain/core/output_parsers";
|
|
8
|
+
import { JsonOutputParser, StructuredOutputParser, } from "@langchain/core/output_parsers";
|
|
9
9
|
import { JsonOutputKeyToolsParser } from "@langchain/core/output_parsers/openai_tools";
|
|
10
10
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
11
11
|
import { getEndpoint } from "./utils/azure.js";
|
|
@@ -466,10 +466,18 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
466
466
|
console.log("[WARNING]: Received non-string content from OpenAI. This is currently not supported.");
|
|
467
467
|
continue;
|
|
468
468
|
}
|
|
469
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
470
|
+
const generationInfo = { ...newTokenIndices };
|
|
471
|
+
if (choice.finish_reason !== undefined) {
|
|
472
|
+
generationInfo.finish_reason = choice.finish_reason;
|
|
473
|
+
}
|
|
474
|
+
if (this.logprobs) {
|
|
475
|
+
generationInfo.logprobs = choice.logprobs;
|
|
476
|
+
}
|
|
469
477
|
const generationChunk = new ChatGenerationChunk({
|
|
470
478
|
message: chunk,
|
|
471
479
|
text: chunk.content,
|
|
472
|
-
generationInfo
|
|
480
|
+
generationInfo,
|
|
473
481
|
});
|
|
474
482
|
yield generationChunk;
|
|
475
483
|
// eslint-disable-next-line no-void
|
|
@@ -495,6 +503,10 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
495
503
|
const stream = this._streamResponseChunks(messages, options, runManager);
|
|
496
504
|
const finalChunks = {};
|
|
497
505
|
for await (const chunk of stream) {
|
|
506
|
+
chunk.message.response_metadata = {
|
|
507
|
+
...chunk.generationInfo,
|
|
508
|
+
...chunk.message.response_metadata,
|
|
509
|
+
};
|
|
498
510
|
const index = chunk.generationInfo?.completion ?? 0;
|
|
499
511
|
if (finalChunks[index] === undefined) {
|
|
500
512
|
finalChunks[index] = chunk;
|
|
@@ -738,21 +750,26 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
738
750
|
llm = this.bind({
|
|
739
751
|
response_format: { type: "json_object" },
|
|
740
752
|
});
|
|
741
|
-
|
|
753
|
+
if (isZodSchema(schema)) {
|
|
754
|
+
outputParser = StructuredOutputParser.fromZodSchema(schema);
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
outputParser = new JsonOutputParser();
|
|
758
|
+
}
|
|
742
759
|
}
|
|
743
760
|
else {
|
|
744
761
|
const functionName = name ?? "extract";
|
|
745
762
|
// Is function calling
|
|
746
763
|
if (isZodSchema(schema)) {
|
|
747
|
-
const
|
|
764
|
+
const asJsonSchema = zodToJsonSchema(schema);
|
|
748
765
|
llm = this.bind({
|
|
749
766
|
tools: [
|
|
750
767
|
{
|
|
751
768
|
type: "function",
|
|
752
769
|
function: {
|
|
753
770
|
name: functionName,
|
|
754
|
-
description:
|
|
755
|
-
parameters:
|
|
771
|
+
description: asJsonSchema.description,
|
|
772
|
+
parameters: asJsonSchema,
|
|
756
773
|
},
|
|
757
774
|
},
|
|
758
775
|
],
|
|
@@ -766,6 +783,7 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
766
783
|
outputParser = new JsonOutputKeyToolsParser({
|
|
767
784
|
returnSingle: true,
|
|
768
785
|
keyName: functionName,
|
|
786
|
+
zodSchema: schema,
|
|
769
787
|
});
|
|
770
788
|
}
|
|
771
789
|
else {
|
|
@@ -814,7 +832,9 @@ export class ChatOpenAI extends BaseChatModel {
|
|
|
814
832
|
]);
|
|
815
833
|
}
|
|
816
834
|
}
|
|
817
|
-
function isZodSchema(
|
|
835
|
+
function isZodSchema(
|
|
836
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
837
|
+
input) {
|
|
818
838
|
// Check for a characteristic method of Zod schemas
|
|
819
839
|
return typeof input?.parse === "function";
|
|
820
840
|
}
|
package/dist/index.cjs
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/legacy.cjs
CHANGED
|
@@ -42,7 +42,7 @@ const openai_js_1 = require("./utils/openai.cjs");
|
|
|
42
42
|
* maxTokens: 50,
|
|
43
43
|
* });
|
|
44
44
|
*
|
|
45
|
-
* const res = await model.
|
|
45
|
+
* const res = await model.invoke(
|
|
46
46
|
* "What would be a good company name for a company that makes colorful socks?"
|
|
47
47
|
* );
|
|
48
48
|
* console.log({ res });
|
package/dist/legacy.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export interface OpenAIChatCallOptions extends OpenAICallOptions {
|
|
|
47
47
|
* maxTokens: 50,
|
|
48
48
|
* });
|
|
49
49
|
*
|
|
50
|
-
* const res = await model.
|
|
50
|
+
* const res = await model.invoke(
|
|
51
51
|
* "What would be a good company name for a company that makes colorful socks?"
|
|
52
52
|
* );
|
|
53
53
|
* console.log({ res });
|
package/dist/legacy.js
CHANGED
|
@@ -39,7 +39,7 @@ import { wrapOpenAIClientError } from "./utils/openai.js";
|
|
|
39
39
|
* maxTokens: 50,
|
|
40
40
|
* });
|
|
41
41
|
*
|
|
42
|
-
* const res = await model.
|
|
42
|
+
* const res = await model.invoke(
|
|
43
43
|
* "What would be a good company name for a company that makes colorful socks?"
|
|
44
44
|
* );
|
|
45
45
|
* console.log({ res });
|
package/dist/llms.cjs
CHANGED
|
@@ -37,7 +37,7 @@ const openai_js_1 = require("./utils/openai.cjs");
|
|
|
37
37
|
* maxRetries: 5,
|
|
38
38
|
* });
|
|
39
39
|
*
|
|
40
|
-
* const res = await model.
|
|
40
|
+
* const res = await model.invoke(
|
|
41
41
|
* "Question: What would be a good company name for a company that makes colorful socks?\nAnswer:"
|
|
42
42
|
* );
|
|
43
43
|
* console.log({ res });
|
package/dist/llms.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export { OpenAIChat };
|
|
|
32
32
|
* maxRetries: 5,
|
|
33
33
|
* });
|
|
34
34
|
*
|
|
35
|
-
* const res = await model.
|
|
35
|
+
* const res = await model.invoke(
|
|
36
36
|
* "Question: What would be a good company name for a company that makes colorful socks?\nAnswer:"
|
|
37
37
|
* );
|
|
38
38
|
* console.log({ res });
|
package/dist/llms.js
CHANGED
|
@@ -34,7 +34,7 @@ export { OpenAIChat };
|
|
|
34
34
|
* maxRetries: 5,
|
|
35
35
|
* });
|
|
36
36
|
*
|
|
37
|
-
* const res = await model.
|
|
37
|
+
* const res = await model.invoke(
|
|
38
38
|
* "Question: What would be a good company name for a company that makes colorful socks?\nAnswer:"
|
|
39
39
|
* );
|
|
40
40
|
* console.log({ res });
|
|
@@ -62,6 +62,17 @@ test("Test ChatOpenAI tool calling", async () => {
|
|
|
62
62
|
console.log(JSON.stringify(res));
|
|
63
63
|
expect(res.additional_kwargs.tool_calls?.length).toBeGreaterThan(1);
|
|
64
64
|
});
|
|
65
|
+
test("Test ChatOpenAI streaming logprobs", async () => {
|
|
66
|
+
const model = new ChatOpenAI({
|
|
67
|
+
maxTokens: 50,
|
|
68
|
+
modelName: "gpt-3.5-turbo",
|
|
69
|
+
streaming: true,
|
|
70
|
+
logprobs: true,
|
|
71
|
+
});
|
|
72
|
+
const res = await model.invoke("Print hello world.");
|
|
73
|
+
console.log(res.response_metadata.logprobs.content);
|
|
74
|
+
expect(res.response_metadata.logprobs.content.length).toBeGreaterThan(0);
|
|
75
|
+
});
|
|
65
76
|
test("Test ChatOpenAI tool calling with ToolMessages", async () => {
|
|
66
77
|
function getCurrentWeather(location) {
|
|
67
78
|
if (location.toLowerCase().includes("tokyo")) {
|
|
@@ -1,25 +1,10 @@
|
|
|
1
|
-
import { test, jest, expect
|
|
1
|
+
import { test, jest, expect } from "@jest/globals";
|
|
2
2
|
import { ChatMessage, HumanMessage, SystemMessage, } from "@langchain/core/messages";
|
|
3
3
|
import { ChatPromptValue } from "@langchain/core/prompt_values";
|
|
4
4
|
import { PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate, } from "@langchain/core/prompts";
|
|
5
5
|
import { CallbackManager } from "@langchain/core/callbacks/manager";
|
|
6
6
|
import { InMemoryCache } from "@langchain/core/caches";
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
9
7
|
import { ChatOpenAI } from "../chat_models.js";
|
|
10
|
-
test("Test ChatOpenAI", async () => {
|
|
11
|
-
const chat = new ChatOpenAI({ modelName: "gpt-3.5-turbo", maxTokens: 10 });
|
|
12
|
-
const message = new HumanMessage("Hello!");
|
|
13
|
-
const res = await chat.call([message]);
|
|
14
|
-
console.log({ res });
|
|
15
|
-
});
|
|
16
|
-
test("Test ChatOpenAI with SystemChatMessage", async () => {
|
|
17
|
-
const chat = new ChatOpenAI({ modelName: "gpt-3.5-turbo", maxTokens: 10 });
|
|
18
|
-
const system_message = new SystemMessage("You are to chat with a user.");
|
|
19
|
-
const message = new HumanMessage("Hello!");
|
|
20
|
-
const res = await chat.call([system_message, message]);
|
|
21
|
-
console.log({ res });
|
|
22
|
-
});
|
|
23
8
|
test("Test ChatOpenAI Generate", async () => {
|
|
24
9
|
const chat = new ChatOpenAI({
|
|
25
10
|
modelName: "gpt-3.5-turbo",
|
|
@@ -65,7 +50,7 @@ test("Test ChatOpenAI tokenUsage", async () => {
|
|
|
65
50
|
}),
|
|
66
51
|
});
|
|
67
52
|
const message = new HumanMessage("Hello");
|
|
68
|
-
const res = await model.
|
|
53
|
+
const res = await model.invoke([message]);
|
|
69
54
|
console.log({ res });
|
|
70
55
|
expect(tokenUsage.promptTokens).toBeGreaterThan(0);
|
|
71
56
|
});
|
|
@@ -108,7 +93,7 @@ test("Test ChatOpenAI in streaming mode", async () => {
|
|
|
108
93
|
],
|
|
109
94
|
});
|
|
110
95
|
const message = new HumanMessage("Hello!");
|
|
111
|
-
const result = await model.
|
|
96
|
+
const result = await model.invoke([message]);
|
|
112
97
|
console.log(result);
|
|
113
98
|
expect(nrNewTokens > 0).toBe(true);
|
|
114
99
|
expect(result.content).toBe(streamedCompletion);
|
|
@@ -175,25 +160,27 @@ test("OpenAI Chat, docs, prompt templates", async () => {
|
|
|
175
160
|
}, 5000);
|
|
176
161
|
test("Test OpenAI with stop", async () => {
|
|
177
162
|
const model = new ChatOpenAI({ maxTokens: 5 });
|
|
178
|
-
const res = await model.
|
|
163
|
+
const res = await model.invoke([new HumanMessage("Print hello world")], {
|
|
164
|
+
stop: ["world"],
|
|
165
|
+
});
|
|
179
166
|
console.log({ res });
|
|
180
167
|
});
|
|
181
168
|
test("Test OpenAI with stop in object", async () => {
|
|
182
169
|
const model = new ChatOpenAI({ maxTokens: 5 });
|
|
183
|
-
const res = await model.
|
|
170
|
+
const res = await model.invoke([new HumanMessage("Print hello world")], {
|
|
184
171
|
stop: ["world"],
|
|
185
172
|
});
|
|
186
173
|
console.log({ res });
|
|
187
174
|
});
|
|
188
175
|
test("Test OpenAI with timeout in call options", async () => {
|
|
189
|
-
const model = new ChatOpenAI({ maxTokens: 5 });
|
|
190
|
-
await expect(() => model.
|
|
176
|
+
const model = new ChatOpenAI({ maxTokens: 5, maxRetries: 0 });
|
|
177
|
+
await expect(() => model.invoke([new HumanMessage("Print hello world")], {
|
|
191
178
|
options: { timeout: 10 },
|
|
192
179
|
})).rejects.toThrow();
|
|
193
180
|
}, 5000);
|
|
194
181
|
test("Test OpenAI with timeout in call options and node adapter", async () => {
|
|
195
|
-
const model = new ChatOpenAI({ maxTokens: 5 });
|
|
196
|
-
await expect(() => model.
|
|
182
|
+
const model = new ChatOpenAI({ maxTokens: 5, maxRetries: 0 });
|
|
183
|
+
await expect(() => model.invoke([new HumanMessage("Print hello world")], {
|
|
197
184
|
options: { timeout: 10 },
|
|
198
185
|
})).rejects.toThrow();
|
|
199
186
|
}, 5000);
|
|
@@ -201,7 +188,7 @@ test("Test OpenAI with signal in call options", async () => {
|
|
|
201
188
|
const model = new ChatOpenAI({ maxTokens: 5 });
|
|
202
189
|
const controller = new AbortController();
|
|
203
190
|
await expect(() => {
|
|
204
|
-
const ret = model.
|
|
191
|
+
const ret = model.invoke([new HumanMessage("Print hello world")], {
|
|
205
192
|
options: { signal: controller.signal },
|
|
206
193
|
});
|
|
207
194
|
controller.abort();
|
|
@@ -215,7 +202,7 @@ test("Test OpenAI with signal in call options and node adapter", async () => {
|
|
|
215
202
|
});
|
|
216
203
|
const controller = new AbortController();
|
|
217
204
|
await expect(() => {
|
|
218
|
-
const ret = model.
|
|
205
|
+
const ret = model.invoke([new HumanMessage("Print hello world")], {
|
|
219
206
|
options: { signal: controller.signal },
|
|
220
207
|
});
|
|
221
208
|
controller.abort();
|
|
@@ -260,7 +247,7 @@ test("Test OpenAI with specific roles in ChatMessage", async () => {
|
|
|
260
247
|
const chat = new ChatOpenAI({ modelName: "gpt-3.5-turbo", maxTokens: 10 });
|
|
261
248
|
const system_message = new ChatMessage("You are to chat with a user.", "system");
|
|
262
249
|
const user_message = new ChatMessage("Hello!", "user");
|
|
263
|
-
const res = await chat.
|
|
250
|
+
const res = await chat.invoke([system_message, user_message]);
|
|
264
251
|
console.log({ res });
|
|
265
252
|
});
|
|
266
253
|
test("Test ChatOpenAI stream method", async () => {
|
|
@@ -305,6 +292,7 @@ test("Test ChatOpenAI stream method, timeout error thrown from SDK", async () =>
|
|
|
305
292
|
maxTokens: 50,
|
|
306
293
|
modelName: "gpt-3.5-turbo",
|
|
307
294
|
timeout: 1,
|
|
295
|
+
maxRetries: 0,
|
|
308
296
|
});
|
|
309
297
|
const stream = await model.stream("How is your day going? Be extremely verbose.");
|
|
310
298
|
for await (const chunk of stream) {
|
|
@@ -630,169 +618,3 @@ test("Test ChatOpenAI token usage reporting for streaming calls", async () => {
|
|
|
630
618
|
expect(streamingTokenUsed).toEqual(nonStreamingTokenUsed);
|
|
631
619
|
}
|
|
632
620
|
});
|
|
633
|
-
describe("ChatOpenAI withStructuredOutput", () => {
|
|
634
|
-
test("withStructuredOutput zod schema function calling", async () => {
|
|
635
|
-
const model = new ChatOpenAI({
|
|
636
|
-
temperature: 0,
|
|
637
|
-
modelName: "gpt-4-turbo-preview",
|
|
638
|
-
});
|
|
639
|
-
const calculatorSchema = z.object({
|
|
640
|
-
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
641
|
-
number1: z.number(),
|
|
642
|
-
number2: z.number(),
|
|
643
|
-
});
|
|
644
|
-
const modelWithStructuredOutput = model.withStructuredOutput(calculatorSchema, {
|
|
645
|
-
name: "calculator",
|
|
646
|
-
});
|
|
647
|
-
const prompt = ChatPromptTemplate.fromMessages([
|
|
648
|
-
"system",
|
|
649
|
-
"You are VERY bad at math and must always use a calculator.",
|
|
650
|
-
"human",
|
|
651
|
-
"Please help me!! What is 2 + 2?",
|
|
652
|
-
]);
|
|
653
|
-
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
654
|
-
const result = await chain.invoke({});
|
|
655
|
-
console.log(result);
|
|
656
|
-
expect("operation" in result).toBe(true);
|
|
657
|
-
expect("number1" in result).toBe(true);
|
|
658
|
-
expect("number2" in result).toBe(true);
|
|
659
|
-
});
|
|
660
|
-
test("withStructuredOutput zod schema JSON mode", async () => {
|
|
661
|
-
const model = new ChatOpenAI({
|
|
662
|
-
temperature: 0,
|
|
663
|
-
modelName: "gpt-4-turbo-preview",
|
|
664
|
-
});
|
|
665
|
-
const calculatorSchema = z.object({
|
|
666
|
-
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
667
|
-
number1: z.number(),
|
|
668
|
-
number2: z.number(),
|
|
669
|
-
});
|
|
670
|
-
const modelWithStructuredOutput = model.withStructuredOutput(calculatorSchema, {
|
|
671
|
-
name: "calculator",
|
|
672
|
-
method: "jsonMode",
|
|
673
|
-
});
|
|
674
|
-
const prompt = ChatPromptTemplate.fromMessages([
|
|
675
|
-
"system",
|
|
676
|
-
`You are VERY bad at math and must always use a calculator.
|
|
677
|
-
Respond with a JSON object containing three keys:
|
|
678
|
-
'operation': the type of operation to execute, either 'add', 'subtract', 'multiply' or 'divide',
|
|
679
|
-
'number1': the first number to operate on,
|
|
680
|
-
'number2': the second number to operate on.
|
|
681
|
-
`,
|
|
682
|
-
"human",
|
|
683
|
-
"Please help me!! What is 2 + 2?",
|
|
684
|
-
]);
|
|
685
|
-
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
686
|
-
const result = await chain.invoke({});
|
|
687
|
-
console.log(result);
|
|
688
|
-
expect("operation" in result).toBe(true);
|
|
689
|
-
expect("number1" in result).toBe(true);
|
|
690
|
-
expect("number2" in result).toBe(true);
|
|
691
|
-
});
|
|
692
|
-
test("withStructuredOutput JSON schema function calling", async () => {
|
|
693
|
-
const model = new ChatOpenAI({
|
|
694
|
-
temperature: 0,
|
|
695
|
-
modelName: "gpt-4-turbo-preview",
|
|
696
|
-
});
|
|
697
|
-
const calculatorSchema = z.object({
|
|
698
|
-
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
699
|
-
number1: z.number(),
|
|
700
|
-
number2: z.number(),
|
|
701
|
-
});
|
|
702
|
-
const modelWithStructuredOutput = model.withStructuredOutput({
|
|
703
|
-
schema: zodToJsonSchema(calculatorSchema),
|
|
704
|
-
name: "calculator",
|
|
705
|
-
});
|
|
706
|
-
const prompt = ChatPromptTemplate.fromMessages([
|
|
707
|
-
"system",
|
|
708
|
-
`You are VERY bad at math and must always use a calculator.`,
|
|
709
|
-
"human",
|
|
710
|
-
"Please help me!! What is 2 + 2?",
|
|
711
|
-
]);
|
|
712
|
-
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
713
|
-
const result = await chain.invoke({});
|
|
714
|
-
console.log(result);
|
|
715
|
-
expect("operation" in result).toBe(true);
|
|
716
|
-
expect("number1" in result).toBe(true);
|
|
717
|
-
expect("number2" in result).toBe(true);
|
|
718
|
-
});
|
|
719
|
-
test("withStructuredOutput JSON schema JSON mode", async () => {
|
|
720
|
-
const model = new ChatOpenAI({
|
|
721
|
-
temperature: 0,
|
|
722
|
-
modelName: "gpt-4-turbo-preview",
|
|
723
|
-
});
|
|
724
|
-
const calculatorSchema = z.object({
|
|
725
|
-
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
726
|
-
number1: z.number(),
|
|
727
|
-
number2: z.number(),
|
|
728
|
-
});
|
|
729
|
-
const modelWithStructuredOutput = model.withStructuredOutput(zodToJsonSchema(calculatorSchema), {
|
|
730
|
-
name: "calculator",
|
|
731
|
-
method: "jsonMode",
|
|
732
|
-
});
|
|
733
|
-
const prompt = ChatPromptTemplate.fromMessages([
|
|
734
|
-
"system",
|
|
735
|
-
`You are VERY bad at math and must always use a calculator.
|
|
736
|
-
Respond with a JSON object containing three keys:
|
|
737
|
-
'operation': the type of operation to execute, either 'add', 'subtract', 'multiply' or 'divide',
|
|
738
|
-
'number1': the first number to operate on,
|
|
739
|
-
'number2': the second number to operate on.
|
|
740
|
-
`,
|
|
741
|
-
"human",
|
|
742
|
-
"Please help me!! What is 2 + 2?",
|
|
743
|
-
]);
|
|
744
|
-
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
745
|
-
const result = await chain.invoke({});
|
|
746
|
-
console.log(result);
|
|
747
|
-
expect("operation" in result).toBe(true);
|
|
748
|
-
expect("number1" in result).toBe(true);
|
|
749
|
-
expect("number2" in result).toBe(true);
|
|
750
|
-
});
|
|
751
|
-
test("withStructuredOutput includeRaw true", async () => {
|
|
752
|
-
const model = new ChatOpenAI({
|
|
753
|
-
temperature: 0,
|
|
754
|
-
modelName: "gpt-4-turbo-preview",
|
|
755
|
-
});
|
|
756
|
-
const calculatorSchema = z.object({
|
|
757
|
-
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
758
|
-
number1: z.number(),
|
|
759
|
-
number2: z.number(),
|
|
760
|
-
});
|
|
761
|
-
const modelWithStructuredOutput = model.withStructuredOutput(calculatorSchema, {
|
|
762
|
-
name: "calculator",
|
|
763
|
-
includeRaw: true,
|
|
764
|
-
});
|
|
765
|
-
const prompt = ChatPromptTemplate.fromMessages([
|
|
766
|
-
"system",
|
|
767
|
-
"You are VERY bad at math and must always use a calculator.",
|
|
768
|
-
"human",
|
|
769
|
-
"Please help me!! What is 2 + 2?",
|
|
770
|
-
]);
|
|
771
|
-
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
772
|
-
const result = await chain.invoke({});
|
|
773
|
-
console.log(result);
|
|
774
|
-
expect("parsed" in result).toBe(true);
|
|
775
|
-
// Need to make TS happy :)
|
|
776
|
-
if (!("parsed" in result)) {
|
|
777
|
-
throw new Error("parsed not in result");
|
|
778
|
-
}
|
|
779
|
-
const { parsed } = result;
|
|
780
|
-
expect("operation" in parsed).toBe(true);
|
|
781
|
-
expect("number1" in parsed).toBe(true);
|
|
782
|
-
expect("number2" in parsed).toBe(true);
|
|
783
|
-
expect("raw" in result).toBe(true);
|
|
784
|
-
// Need to make TS happy :)
|
|
785
|
-
if (!("raw" in result)) {
|
|
786
|
-
throw new Error("raw not in result");
|
|
787
|
-
}
|
|
788
|
-
const { raw } = result;
|
|
789
|
-
expect(raw.additional_kwargs.tool_calls?.length).toBeGreaterThan(0);
|
|
790
|
-
expect(raw.additional_kwargs.tool_calls?.[0].function.name).toBe("calculator");
|
|
791
|
-
expect("operation" in
|
|
792
|
-
JSON.parse(raw.additional_kwargs.tool_calls?.[0].function.arguments ?? "")).toBe(true);
|
|
793
|
-
expect("number1" in
|
|
794
|
-
JSON.parse(raw.additional_kwargs.tool_calls?.[0].function.arguments ?? "")).toBe(true);
|
|
795
|
-
expect("number2" in
|
|
796
|
-
JSON.parse(raw.additional_kwargs.tool_calls?.[0].function.arguments ?? "")).toBe(true);
|
|
797
|
-
});
|
|
798
|
-
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
3
|
+
import { ChatPromptTemplate } from "@langchain/core/prompts";
|
|
4
|
+
import { ChatOpenAI } from "../chat_models.js";
|
|
5
|
+
test("withStructuredOutput zod schema function calling", async () => {
|
|
6
|
+
const model = new ChatOpenAI({
|
|
7
|
+
temperature: 0,
|
|
8
|
+
modelName: "gpt-4-turbo-preview",
|
|
9
|
+
});
|
|
10
|
+
const calculatorSchema = z.object({
|
|
11
|
+
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
12
|
+
number1: z.number(),
|
|
13
|
+
number2: z.number(),
|
|
14
|
+
});
|
|
15
|
+
const modelWithStructuredOutput = model.withStructuredOutput(calculatorSchema, {
|
|
16
|
+
name: "calculator",
|
|
17
|
+
});
|
|
18
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
19
|
+
"system",
|
|
20
|
+
"You are VERY bad at math and must always use a calculator.",
|
|
21
|
+
"human",
|
|
22
|
+
"Please help me!! What is 2 + 2?",
|
|
23
|
+
]);
|
|
24
|
+
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
25
|
+
const result = await chain.invoke({});
|
|
26
|
+
console.log(result);
|
|
27
|
+
expect("operation" in result).toBe(true);
|
|
28
|
+
expect("number1" in result).toBe(true);
|
|
29
|
+
expect("number2" in result).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
test("withStructuredOutput zod schema JSON mode", async () => {
|
|
32
|
+
const model = new ChatOpenAI({
|
|
33
|
+
temperature: 0,
|
|
34
|
+
modelName: "gpt-4-turbo-preview",
|
|
35
|
+
});
|
|
36
|
+
const calculatorSchema = z.object({
|
|
37
|
+
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
38
|
+
number1: z.number(),
|
|
39
|
+
number2: z.number(),
|
|
40
|
+
});
|
|
41
|
+
const modelWithStructuredOutput = model.withStructuredOutput(calculatorSchema, {
|
|
42
|
+
name: "calculator",
|
|
43
|
+
method: "jsonMode",
|
|
44
|
+
});
|
|
45
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
46
|
+
"system",
|
|
47
|
+
`You are VERY bad at math and must always use a calculator.
|
|
48
|
+
Respond with a JSON object containing three keys:
|
|
49
|
+
'operation': the type of operation to execute, either 'add', 'subtract', 'multiply' or 'divide',
|
|
50
|
+
'number1': the first number to operate on,
|
|
51
|
+
'number2': the second number to operate on.
|
|
52
|
+
`,
|
|
53
|
+
"human",
|
|
54
|
+
"Please help me!! What is 2 + 2?",
|
|
55
|
+
]);
|
|
56
|
+
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
57
|
+
const result = await chain.invoke({});
|
|
58
|
+
console.log(result);
|
|
59
|
+
expect("operation" in result).toBe(true);
|
|
60
|
+
expect("number1" in result).toBe(true);
|
|
61
|
+
expect("number2" in result).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
test("withStructuredOutput JSON schema function calling", async () => {
|
|
64
|
+
const model = new ChatOpenAI({
|
|
65
|
+
temperature: 0,
|
|
66
|
+
modelName: "gpt-4-turbo-preview",
|
|
67
|
+
});
|
|
68
|
+
const calculatorSchema = z.object({
|
|
69
|
+
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
70
|
+
number1: z.number(),
|
|
71
|
+
number2: z.number(),
|
|
72
|
+
});
|
|
73
|
+
const modelWithStructuredOutput = model.withStructuredOutput({
|
|
74
|
+
schema: zodToJsonSchema(calculatorSchema),
|
|
75
|
+
name: "calculator",
|
|
76
|
+
});
|
|
77
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
78
|
+
"system",
|
|
79
|
+
`You are VERY bad at math and must always use a calculator.`,
|
|
80
|
+
"human",
|
|
81
|
+
"Please help me!! What is 2 + 2?",
|
|
82
|
+
]);
|
|
83
|
+
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
84
|
+
const result = await chain.invoke({});
|
|
85
|
+
console.log(result);
|
|
86
|
+
expect("operation" in result).toBe(true);
|
|
87
|
+
expect("number1" in result).toBe(true);
|
|
88
|
+
expect("number2" in result).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
test("withStructuredOutput JSON schema JSON mode", async () => {
|
|
91
|
+
const model = new ChatOpenAI({
|
|
92
|
+
temperature: 0,
|
|
93
|
+
modelName: "gpt-4-turbo-preview",
|
|
94
|
+
});
|
|
95
|
+
const calculatorSchema = z.object({
|
|
96
|
+
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
97
|
+
number1: z.number(),
|
|
98
|
+
number2: z.number(),
|
|
99
|
+
});
|
|
100
|
+
const modelWithStructuredOutput = model.withStructuredOutput(zodToJsonSchema(calculatorSchema), {
|
|
101
|
+
name: "calculator",
|
|
102
|
+
method: "jsonMode",
|
|
103
|
+
});
|
|
104
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
105
|
+
"system",
|
|
106
|
+
`You are VERY bad at math and must always use a calculator.
|
|
107
|
+
Respond with a JSON object containing three keys:
|
|
108
|
+
'operation': the type of operation to execute, either 'add', 'subtract', 'multiply' or 'divide',
|
|
109
|
+
'number1': the first number to operate on,
|
|
110
|
+
'number2': the second number to operate on.
|
|
111
|
+
`,
|
|
112
|
+
"human",
|
|
113
|
+
"Please help me!! What is 2 + 2?",
|
|
114
|
+
]);
|
|
115
|
+
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
116
|
+
const result = await chain.invoke({});
|
|
117
|
+
console.log(result);
|
|
118
|
+
expect("operation" in result).toBe(true);
|
|
119
|
+
expect("number1" in result).toBe(true);
|
|
120
|
+
expect("number2" in result).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
test("withStructuredOutput includeRaw true", async () => {
|
|
123
|
+
const model = new ChatOpenAI({
|
|
124
|
+
temperature: 0,
|
|
125
|
+
modelName: "gpt-4-turbo-preview",
|
|
126
|
+
});
|
|
127
|
+
const calculatorSchema = z.object({
|
|
128
|
+
operation: z.enum(["add", "subtract", "multiply", "divide"]),
|
|
129
|
+
number1: z.number(),
|
|
130
|
+
number2: z.number(),
|
|
131
|
+
});
|
|
132
|
+
const modelWithStructuredOutput = model.withStructuredOutput(calculatorSchema, {
|
|
133
|
+
name: "calculator",
|
|
134
|
+
includeRaw: true,
|
|
135
|
+
});
|
|
136
|
+
const prompt = ChatPromptTemplate.fromMessages([
|
|
137
|
+
"system",
|
|
138
|
+
"You are VERY bad at math and must always use a calculator.",
|
|
139
|
+
"human",
|
|
140
|
+
"Please help me!! What is 2 + 2?",
|
|
141
|
+
]);
|
|
142
|
+
const chain = prompt.pipe(modelWithStructuredOutput);
|
|
143
|
+
const result = await chain.invoke({});
|
|
144
|
+
console.log(result);
|
|
145
|
+
expect("parsed" in result).toBe(true);
|
|
146
|
+
// Need to make TS happy :)
|
|
147
|
+
if (!("parsed" in result)) {
|
|
148
|
+
throw new Error("parsed not in result");
|
|
149
|
+
}
|
|
150
|
+
const { parsed } = result;
|
|
151
|
+
expect("operation" in parsed).toBe(true);
|
|
152
|
+
expect("number1" in parsed).toBe(true);
|
|
153
|
+
expect("number2" in parsed).toBe(true);
|
|
154
|
+
expect("raw" in result).toBe(true);
|
|
155
|
+
// Need to make TS happy :)
|
|
156
|
+
if (!("raw" in result)) {
|
|
157
|
+
throw new Error("raw not in result");
|
|
158
|
+
}
|
|
159
|
+
const { raw } = result;
|
|
160
|
+
expect(raw.additional_kwargs.tool_calls?.length).toBeGreaterThan(0);
|
|
161
|
+
expect(raw.additional_kwargs.tool_calls?.[0].function.name).toBe("calculator");
|
|
162
|
+
expect("operation" in
|
|
163
|
+
JSON.parse(raw.additional_kwargs.tool_calls?.[0].function.arguments ?? "")).toBe(true);
|
|
164
|
+
expect("number1" in
|
|
165
|
+
JSON.parse(raw.additional_kwargs.tool_calls?.[0].function.arguments ?? "")).toBe(true);
|
|
166
|
+
expect("number2" in
|
|
167
|
+
JSON.parse(raw.additional_kwargs.tool_calls?.[0].function.arguments ?? "")).toBe(true);
|
|
168
|
+
});
|
|
@@ -3,7 +3,7 @@ import { CallbackManager } from "@langchain/core/callbacks/manager";
|
|
|
3
3
|
import { OpenAIChat } from "../legacy.js";
|
|
4
4
|
test("Test OpenAI", async () => {
|
|
5
5
|
const model = new OpenAIChat({ modelName: "gpt-3.5-turbo", maxTokens: 10 });
|
|
6
|
-
const res = await model.
|
|
6
|
+
const res = await model.invoke("Print hello world");
|
|
7
7
|
console.log({ res });
|
|
8
8
|
});
|
|
9
9
|
test("Test OpenAI with prefix messages", async () => {
|
|
@@ -14,7 +14,7 @@ test("Test OpenAI with prefix messages", async () => {
|
|
|
14
14
|
],
|
|
15
15
|
maxTokens: 10,
|
|
16
16
|
});
|
|
17
|
-
const res = await model.
|
|
17
|
+
const res = await model.invoke("What is my name");
|
|
18
18
|
console.log({ res });
|
|
19
19
|
});
|
|
20
20
|
test("Test OpenAI in streaming mode", async () => {
|
|
@@ -31,7 +31,7 @@ test("Test OpenAI in streaming mode", async () => {
|
|
|
31
31
|
},
|
|
32
32
|
}),
|
|
33
33
|
});
|
|
34
|
-
const res = await model.
|
|
34
|
+
const res = await model.invoke("Print hello world");
|
|
35
35
|
console.log({ res });
|
|
36
36
|
expect(nrNewTokens > 0).toBe(true);
|
|
37
37
|
expect(res).toBe(streamedCompletion);
|
|
@@ -43,18 +43,18 @@ test("Test OpenAI with stop", async () => {
|
|
|
43
43
|
});
|
|
44
44
|
test("Test OpenAI with stop in object", async () => {
|
|
45
45
|
const model = new OpenAIChat({ maxTokens: 5 });
|
|
46
|
-
const res = await model.
|
|
46
|
+
const res = await model.invoke("Print hello world", { stop: ["world"] });
|
|
47
47
|
console.log({ res });
|
|
48
48
|
});
|
|
49
49
|
test("Test OpenAI with timeout in call options", async () => {
|
|
50
50
|
const model = new OpenAIChat({ maxTokens: 5 });
|
|
51
|
-
await expect(() => model.
|
|
51
|
+
await expect(() => model.invoke("Print hello world", {
|
|
52
52
|
timeout: 10,
|
|
53
53
|
})).rejects.toThrow();
|
|
54
54
|
}, 5000);
|
|
55
55
|
test("Test OpenAI with timeout in call options and node adapter", async () => {
|
|
56
56
|
const model = new OpenAIChat({ maxTokens: 5 });
|
|
57
|
-
await expect(() => model.
|
|
57
|
+
await expect(() => model.invoke("Print hello world", {
|
|
58
58
|
timeout: 10,
|
|
59
59
|
})).rejects.toThrow();
|
|
60
60
|
}, 5000);
|
|
@@ -62,7 +62,7 @@ test("Test OpenAI with signal in call options", async () => {
|
|
|
62
62
|
const model = new OpenAIChat({ maxTokens: 5 });
|
|
63
63
|
const controller = new AbortController();
|
|
64
64
|
await expect(() => {
|
|
65
|
-
const ret = model.
|
|
65
|
+
const ret = model.invoke("Print hello world", {
|
|
66
66
|
signal: controller.signal,
|
|
67
67
|
});
|
|
68
68
|
controller.abort();
|
|
@@ -73,7 +73,7 @@ test("Test OpenAI with signal in call options and node adapter", async () => {
|
|
|
73
73
|
const model = new OpenAIChat({ maxTokens: 5 });
|
|
74
74
|
const controller = new AbortController();
|
|
75
75
|
await expect(() => {
|
|
76
|
-
const ret = model.
|
|
76
|
+
const ret = model.invoke("Print hello world", {
|
|
77
77
|
signal: controller.signal,
|
|
78
78
|
});
|
|
79
79
|
controller.abort();
|
|
@@ -8,7 +8,7 @@ test("Test OpenAI", async () => {
|
|
|
8
8
|
maxTokens: 5,
|
|
9
9
|
modelName: "gpt-3.5-turbo-instruct",
|
|
10
10
|
});
|
|
11
|
-
const res = await model.
|
|
11
|
+
const res = await model.invoke("Print hello world");
|
|
12
12
|
console.log({ res });
|
|
13
13
|
});
|
|
14
14
|
test("Test OpenAI with stop", async () => {
|
|
@@ -24,24 +24,26 @@ test("Test OpenAI with stop in object", async () => {
|
|
|
24
24
|
maxTokens: 5,
|
|
25
25
|
modelName: "gpt-3.5-turbo-instruct",
|
|
26
26
|
});
|
|
27
|
-
const res = await model.
|
|
27
|
+
const res = await model.invoke("Print hello world", { stop: ["world"] });
|
|
28
28
|
console.log({ res });
|
|
29
29
|
});
|
|
30
30
|
test("Test OpenAI with timeout in call options", async () => {
|
|
31
31
|
const model = new OpenAI({
|
|
32
32
|
maxTokens: 5,
|
|
33
|
+
maxRetries: 0,
|
|
33
34
|
modelName: "gpt-3.5-turbo-instruct",
|
|
34
35
|
});
|
|
35
|
-
await expect(() => model.
|
|
36
|
+
await expect(() => model.invoke("Print hello world", {
|
|
36
37
|
timeout: 10,
|
|
37
38
|
})).rejects.toThrow();
|
|
38
39
|
}, 5000);
|
|
39
40
|
test("Test OpenAI with timeout in call options and node adapter", async () => {
|
|
40
41
|
const model = new OpenAI({
|
|
41
42
|
maxTokens: 5,
|
|
43
|
+
maxRetries: 0,
|
|
42
44
|
modelName: "gpt-3.5-turbo-instruct",
|
|
43
45
|
});
|
|
44
|
-
await expect(() => model.
|
|
46
|
+
await expect(() => model.invoke("Print hello world", {
|
|
45
47
|
timeout: 10,
|
|
46
48
|
})).rejects.toThrow();
|
|
47
49
|
}, 5000);
|
|
@@ -52,7 +54,7 @@ test("Test OpenAI with signal in call options", async () => {
|
|
|
52
54
|
});
|
|
53
55
|
const controller = new AbortController();
|
|
54
56
|
await expect(() => {
|
|
55
|
-
const ret = model.
|
|
57
|
+
const ret = model.invoke("Print hello world", {
|
|
56
58
|
signal: controller.signal,
|
|
57
59
|
});
|
|
58
60
|
controller.abort();
|
|
@@ -66,7 +68,7 @@ test("Test OpenAI with signal in call options and node adapter", async () => {
|
|
|
66
68
|
});
|
|
67
69
|
const controller = new AbortController();
|
|
68
70
|
await expect(() => {
|
|
69
|
-
const ret = model.
|
|
71
|
+
const ret = model.invoke("Print hello world", {
|
|
70
72
|
signal: controller.signal,
|
|
71
73
|
});
|
|
72
74
|
controller.abort();
|
|
@@ -80,8 +82,8 @@ test("Test OpenAI with concurrency == 1", async () => {
|
|
|
80
82
|
maxConcurrency: 1,
|
|
81
83
|
});
|
|
82
84
|
const res = await Promise.all([
|
|
83
|
-
model.
|
|
84
|
-
model.
|
|
85
|
+
model.invoke("Print hello world"),
|
|
86
|
+
model.invoke("Print hello world"),
|
|
85
87
|
]);
|
|
86
88
|
console.log({ res });
|
|
87
89
|
});
|
|
@@ -96,21 +98,21 @@ test("Test OpenAI with maxTokens -1", async () => {
|
|
|
96
98
|
test("Test OpenAI with chat model returns OpenAIChat", async () => {
|
|
97
99
|
const model = new OpenAI({ modelName: "gpt-3.5-turbo" });
|
|
98
100
|
expect(model).toBeInstanceOf(OpenAIChat);
|
|
99
|
-
const res = await model.
|
|
101
|
+
const res = await model.invoke("Print hello world");
|
|
100
102
|
console.log({ res });
|
|
101
103
|
expect(typeof res).toBe("string");
|
|
102
104
|
});
|
|
103
105
|
test("Test OpenAI with instruct model returns OpenAI", async () => {
|
|
104
106
|
const model = new OpenAI({ modelName: "gpt-3.5-turbo-instruct" });
|
|
105
107
|
expect(model).toBeInstanceOf(OpenAI);
|
|
106
|
-
const res = await model.
|
|
108
|
+
const res = await model.invoke("Print hello world");
|
|
107
109
|
console.log({ res });
|
|
108
110
|
expect(typeof res).toBe("string");
|
|
109
111
|
});
|
|
110
112
|
test("Test OpenAI with versioned instruct model returns OpenAI", async () => {
|
|
111
113
|
const model = new OpenAI({ modelName: "gpt-3.5-turbo-instruct-0914" });
|
|
112
114
|
expect(model).toBeInstanceOf(OpenAI);
|
|
113
|
-
const res = await model.
|
|
115
|
+
const res = await model.invoke("Print hello world");
|
|
114
116
|
console.log({ res });
|
|
115
117
|
expect(typeof res).toBe("string");
|
|
116
118
|
});
|
|
@@ -129,7 +131,7 @@ test("Test ChatOpenAI tokenUsage", async () => {
|
|
|
129
131
|
},
|
|
130
132
|
}),
|
|
131
133
|
});
|
|
132
|
-
const res = await model.
|
|
134
|
+
const res = await model.invoke("Hello");
|
|
133
135
|
console.log({ res });
|
|
134
136
|
expect(tokenUsage.promptTokens).toBe(1);
|
|
135
137
|
});
|
|
@@ -147,7 +149,7 @@ test("Test OpenAI in streaming mode", async () => {
|
|
|
147
149
|
},
|
|
148
150
|
}),
|
|
149
151
|
});
|
|
150
|
-
const res = await model.
|
|
152
|
+
const res = await model.invoke("Print hello world");
|
|
151
153
|
console.log({ res });
|
|
152
154
|
expect(nrNewTokens > 0).toBe(true);
|
|
153
155
|
expect(res).toBe(streamedCompletion);
|
|
@@ -230,6 +232,7 @@ test("Test OpenAI stream method with abort", async () => {
|
|
|
230
232
|
await expect(async () => {
|
|
231
233
|
const model = new OpenAI({
|
|
232
234
|
maxTokens: 250,
|
|
235
|
+
maxRetries: 0,
|
|
233
236
|
modelName: "gpt-3.5-turbo-instruct",
|
|
234
237
|
});
|
|
235
238
|
const stream = await model.stream("How is your day going? Be extremely verbose.", {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DallEAPIWrapper = void 0;
|
|
4
|
+
const env_1 = require("@langchain/core/utils/env");
|
|
5
|
+
const openai_1 = require("openai");
|
|
6
|
+
const tools_1 = require("@langchain/core/tools");
|
|
7
|
+
/**
|
|
8
|
+
* A tool for generating images with Open AIs Dall-E 2 or 3 API.
|
|
9
|
+
*/
|
|
10
|
+
class DallEAPIWrapper extends tools_1.Tool {
|
|
11
|
+
static lc_name() {
|
|
12
|
+
return "DallEAPIWrapper";
|
|
13
|
+
}
|
|
14
|
+
constructor(fields) {
|
|
15
|
+
super(fields);
|
|
16
|
+
Object.defineProperty(this, "name", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: "dalle_api_wrapper"
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(this, "description", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: "A wrapper around OpenAI DALL-E API. Useful for when you need to generate images from a text description. Input should be an image description."
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(this, "client", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
configurable: true,
|
|
31
|
+
writable: true,
|
|
32
|
+
value: void 0
|
|
33
|
+
});
|
|
34
|
+
Object.defineProperty(this, "modelName", {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
configurable: true,
|
|
37
|
+
writable: true,
|
|
38
|
+
value: "dall-e-3"
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(this, "style", {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true,
|
|
43
|
+
writable: true,
|
|
44
|
+
value: "vivid"
|
|
45
|
+
});
|
|
46
|
+
Object.defineProperty(this, "quality", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
configurable: true,
|
|
49
|
+
writable: true,
|
|
50
|
+
value: "standard"
|
|
51
|
+
});
|
|
52
|
+
Object.defineProperty(this, "n", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
configurable: true,
|
|
55
|
+
writable: true,
|
|
56
|
+
value: 1
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty(this, "size", {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
configurable: true,
|
|
61
|
+
writable: true,
|
|
62
|
+
value: "1024x1024"
|
|
63
|
+
});
|
|
64
|
+
Object.defineProperty(this, "responseFormat", {
|
|
65
|
+
enumerable: true,
|
|
66
|
+
configurable: true,
|
|
67
|
+
writable: true,
|
|
68
|
+
value: "url"
|
|
69
|
+
});
|
|
70
|
+
Object.defineProperty(this, "user", {
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true,
|
|
73
|
+
writable: true,
|
|
74
|
+
value: void 0
|
|
75
|
+
});
|
|
76
|
+
const openAIApiKey = fields?.openAIApiKey ?? (0, env_1.getEnvironmentVariable)("OPENAI_API_KEY");
|
|
77
|
+
const organization = fields?.organization ?? (0, env_1.getEnvironmentVariable)("OPENAI_ORGANIZATION");
|
|
78
|
+
const clientConfig = {
|
|
79
|
+
apiKey: openAIApiKey,
|
|
80
|
+
organization,
|
|
81
|
+
dangerouslyAllowBrowser: true,
|
|
82
|
+
};
|
|
83
|
+
this.client = new openai_1.OpenAI(clientConfig);
|
|
84
|
+
this.modelName = fields?.modelName ?? this.modelName;
|
|
85
|
+
this.style = fields?.style ?? this.style;
|
|
86
|
+
this.quality = fields?.quality ?? this.quality;
|
|
87
|
+
this.n = fields?.n ?? this.n;
|
|
88
|
+
this.size = fields?.size ?? this.size;
|
|
89
|
+
this.responseFormat = fields?.responseFormat ?? this.responseFormat;
|
|
90
|
+
this.user = fields?.user;
|
|
91
|
+
}
|
|
92
|
+
/** @ignore */
|
|
93
|
+
async _call(input) {
|
|
94
|
+
const response = await this.client.images.generate({
|
|
95
|
+
model: this.modelName,
|
|
96
|
+
prompt: input,
|
|
97
|
+
n: this.n,
|
|
98
|
+
size: this.size,
|
|
99
|
+
response_format: this.responseFormat,
|
|
100
|
+
style: this.style,
|
|
101
|
+
quality: this.quality,
|
|
102
|
+
user: this.user,
|
|
103
|
+
});
|
|
104
|
+
let data = "";
|
|
105
|
+
if (this.responseFormat === "url") {
|
|
106
|
+
[data] = response.data
|
|
107
|
+
.map((item) => item.url)
|
|
108
|
+
.filter((url) => url !== "undefined");
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
[data] = response.data
|
|
112
|
+
.map((item) => item.b64_json)
|
|
113
|
+
.filter((b64_json) => b64_json !== "undefined");
|
|
114
|
+
}
|
|
115
|
+
return data;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.DallEAPIWrapper = DallEAPIWrapper;
|
|
119
|
+
Object.defineProperty(DallEAPIWrapper, "toolName", {
|
|
120
|
+
enumerable: true,
|
|
121
|
+
configurable: true,
|
|
122
|
+
writable: true,
|
|
123
|
+
value: "dalle_api_wrapper"
|
|
124
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { OpenAI as OpenAIClient } from "openai";
|
|
2
|
+
import { Tool, ToolParams } from "@langchain/core/tools";
|
|
3
|
+
/**
|
|
4
|
+
* An interface for the Dall-E API Wrapper.
|
|
5
|
+
*/
|
|
6
|
+
export interface DallEAPIWrapperParams extends ToolParams {
|
|
7
|
+
/**
|
|
8
|
+
* The OpenAI API key
|
|
9
|
+
*/
|
|
10
|
+
openAIApiKey?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The model to use.
|
|
13
|
+
* @params "dall-e-2" | "dall-e-3"
|
|
14
|
+
* @default "dall-e-3"
|
|
15
|
+
*/
|
|
16
|
+
modelName?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The style of the generated images. Must be one of vivid or natural.
|
|
19
|
+
* Vivid causes the model to lean towards generating hyper-real and dramatic images.
|
|
20
|
+
* Natural causes the model to produce more natural, less hyper-real looking images.
|
|
21
|
+
* @default "vivid"
|
|
22
|
+
*/
|
|
23
|
+
style?: "natural" | "vivid";
|
|
24
|
+
/**
|
|
25
|
+
* The quality of the image that will be generated. ‘hd’ creates images with finer
|
|
26
|
+
* details and greater consistency across the image.
|
|
27
|
+
* @default "standard"
|
|
28
|
+
*/
|
|
29
|
+
quality?: "standard" | "hd";
|
|
30
|
+
/**
|
|
31
|
+
* The number of images to generate.
|
|
32
|
+
* Must be between 1 and 10.
|
|
33
|
+
* For dall-e-3, only `n: 1` is supported.
|
|
34
|
+
* @default 1
|
|
35
|
+
*/
|
|
36
|
+
n?: number;
|
|
37
|
+
/**
|
|
38
|
+
* The size of the generated images.
|
|
39
|
+
* Must be one of 256x256, 512x512, or 1024x1024 for DALL·E-2 models.
|
|
40
|
+
* Must be one of 1024x1024, 1792x1024, or 1024x1792 for DALL·E-3 models.
|
|
41
|
+
* @default "1024x1024"
|
|
42
|
+
*/
|
|
43
|
+
size?: "256x256" | "512x512" | "1024x1024" | "1792x1024" | "1024x1792";
|
|
44
|
+
/**
|
|
45
|
+
* The format in which the generated images are returned.
|
|
46
|
+
* Must be one of "url" or "b64_json".
|
|
47
|
+
* @default "url"
|
|
48
|
+
*/
|
|
49
|
+
responseFormat?: "url" | "b64_json";
|
|
50
|
+
/**
|
|
51
|
+
* A unique identifier representing your end-user, which will help
|
|
52
|
+
* OpenAI to monitor and detect abuse.
|
|
53
|
+
*/
|
|
54
|
+
user?: string;
|
|
55
|
+
/**
|
|
56
|
+
* The organization to use
|
|
57
|
+
*/
|
|
58
|
+
organization?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A tool for generating images with Open AIs Dall-E 2 or 3 API.
|
|
62
|
+
*/
|
|
63
|
+
export declare class DallEAPIWrapper extends Tool {
|
|
64
|
+
static lc_name(): string;
|
|
65
|
+
name: string;
|
|
66
|
+
description: string;
|
|
67
|
+
protected client: OpenAIClient;
|
|
68
|
+
static readonly toolName = "dalle_api_wrapper";
|
|
69
|
+
private modelName;
|
|
70
|
+
private style;
|
|
71
|
+
private quality;
|
|
72
|
+
private n;
|
|
73
|
+
private size;
|
|
74
|
+
private responseFormat;
|
|
75
|
+
private user?;
|
|
76
|
+
constructor(fields?: DallEAPIWrapperParams);
|
|
77
|
+
/** @ignore */
|
|
78
|
+
_call(input: string): Promise<string>;
|
|
79
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { getEnvironmentVariable } from "@langchain/core/utils/env";
|
|
2
|
+
import { OpenAI as OpenAIClient } from "openai";
|
|
3
|
+
import { Tool } from "@langchain/core/tools";
|
|
4
|
+
/**
|
|
5
|
+
* A tool for generating images with Open AIs Dall-E 2 or 3 API.
|
|
6
|
+
*/
|
|
7
|
+
export class DallEAPIWrapper extends Tool {
|
|
8
|
+
static lc_name() {
|
|
9
|
+
return "DallEAPIWrapper";
|
|
10
|
+
}
|
|
11
|
+
constructor(fields) {
|
|
12
|
+
super(fields);
|
|
13
|
+
Object.defineProperty(this, "name", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
value: "dalle_api_wrapper"
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(this, "description", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: "A wrapper around OpenAI DALL-E API. Useful for when you need to generate images from a text description. Input should be an image description."
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(this, "client", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
value: void 0
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(this, "modelName", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: "dall-e-3"
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(this, "style", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
writable: true,
|
|
41
|
+
value: "vivid"
|
|
42
|
+
});
|
|
43
|
+
Object.defineProperty(this, "quality", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: "standard"
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(this, "n", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
configurable: true,
|
|
52
|
+
writable: true,
|
|
53
|
+
value: 1
|
|
54
|
+
});
|
|
55
|
+
Object.defineProperty(this, "size", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: "1024x1024"
|
|
60
|
+
});
|
|
61
|
+
Object.defineProperty(this, "responseFormat", {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
writable: true,
|
|
65
|
+
value: "url"
|
|
66
|
+
});
|
|
67
|
+
Object.defineProperty(this, "user", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value: void 0
|
|
72
|
+
});
|
|
73
|
+
const openAIApiKey = fields?.openAIApiKey ?? getEnvironmentVariable("OPENAI_API_KEY");
|
|
74
|
+
const organization = fields?.organization ?? getEnvironmentVariable("OPENAI_ORGANIZATION");
|
|
75
|
+
const clientConfig = {
|
|
76
|
+
apiKey: openAIApiKey,
|
|
77
|
+
organization,
|
|
78
|
+
dangerouslyAllowBrowser: true,
|
|
79
|
+
};
|
|
80
|
+
this.client = new OpenAIClient(clientConfig);
|
|
81
|
+
this.modelName = fields?.modelName ?? this.modelName;
|
|
82
|
+
this.style = fields?.style ?? this.style;
|
|
83
|
+
this.quality = fields?.quality ?? this.quality;
|
|
84
|
+
this.n = fields?.n ?? this.n;
|
|
85
|
+
this.size = fields?.size ?? this.size;
|
|
86
|
+
this.responseFormat = fields?.responseFormat ?? this.responseFormat;
|
|
87
|
+
this.user = fields?.user;
|
|
88
|
+
}
|
|
89
|
+
/** @ignore */
|
|
90
|
+
async _call(input) {
|
|
91
|
+
const response = await this.client.images.generate({
|
|
92
|
+
model: this.modelName,
|
|
93
|
+
prompt: input,
|
|
94
|
+
n: this.n,
|
|
95
|
+
size: this.size,
|
|
96
|
+
response_format: this.responseFormat,
|
|
97
|
+
style: this.style,
|
|
98
|
+
quality: this.quality,
|
|
99
|
+
user: this.user,
|
|
100
|
+
});
|
|
101
|
+
let data = "";
|
|
102
|
+
if (this.responseFormat === "url") {
|
|
103
|
+
[data] = response.data
|
|
104
|
+
.map((item) => item.url)
|
|
105
|
+
.filter((url) => url !== "undefined");
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
[data] = response.data
|
|
109
|
+
.map((item) => item.b64_json)
|
|
110
|
+
.filter((b64_json) => b64_json !== "undefined");
|
|
111
|
+
}
|
|
112
|
+
return data;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
Object.defineProperty(DallEAPIWrapper, "toolName", {
|
|
116
|
+
enumerable: true,
|
|
117
|
+
configurable: true,
|
|
118
|
+
writable: true,
|
|
119
|
+
value: "dalle_api_wrapper"
|
|
120
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./dalle.cjs"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dalle.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dalle.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { test, expect } from "@jest/globals";
|
|
2
|
+
import { DallEAPIWrapper } from "../dalle.js";
|
|
3
|
+
test.skip("Dalle can generate images", async () => {
|
|
4
|
+
const dalle = new DallEAPIWrapper();
|
|
5
|
+
const res = await dalle.invoke("A painting of a cat");
|
|
6
|
+
expect(res).toBeDefined();
|
|
7
|
+
expect(res).toContain("https://");
|
|
8
|
+
});
|
|
9
|
+
test.skip("Dalle can generate images with base 64 response format", async () => {
|
|
10
|
+
const dalle = new DallEAPIWrapper({
|
|
11
|
+
responseFormat: "b64_json",
|
|
12
|
+
});
|
|
13
|
+
const res = await dalle.invoke("A painting of a cat");
|
|
14
|
+
expect(res).toBeDefined();
|
|
15
|
+
expect(res).not.toContain("https://");
|
|
16
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/openai",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
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.45",
|
|
43
43
|
"js-tiktoken": "^1.0.7",
|
|
44
44
|
"openai": "^4.26.0",
|
|
45
45
|
"zod": "^3.22.4",
|