@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.
@@ -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: newTokenIndices,
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
- outputParser = new output_parsers_1.JsonOutputParser();
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 asZodSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(schema);
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: asZodSchema.description,
759
- parameters: asZodSchema,
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(input) {
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
  }
@@ -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: newTokenIndices,
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
- outputParser = new JsonOutputParser();
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 asZodSchema = zodToJsonSchema(schema);
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: asZodSchema.description,
755
- parameters: asZodSchema,
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(input) {
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
@@ -26,3 +26,4 @@ __exportStar(require("./embeddings.cjs"), exports);
26
26
  __exportStar(require("./types.cjs"), exports);
27
27
  __exportStar(require("./utils/openai.cjs"), exports);
28
28
  __exportStar(require("./utils/azure.cjs"), exports);
29
+ __exportStar(require("./tools/index.cjs"), exports);
package/dist/index.d.ts CHANGED
@@ -7,3 +7,4 @@ export * from "./embeddings.js";
7
7
  export * from "./types.js";
8
8
  export * from "./utils/openai.js";
9
9
  export * from "./utils/azure.js";
10
+ export * from "./tools/index.js";
package/dist/index.js CHANGED
@@ -7,3 +7,4 @@ export * from "./embeddings.js";
7
7
  export * from "./types.js";
8
8
  export * from "./utils/openai.js";
9
9
  export * from "./utils/azure.js";
10
+ export * from "./tools/index.js";
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.call(
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.call(
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.call(
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.call(
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.call(
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.call(
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, describe } from "@jest/globals";
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.call([message]);
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.call([message]);
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.call([new HumanMessage("Print hello world")], ["world"]);
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.call([new HumanMessage("Print hello world")], {
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.call([new HumanMessage("Print hello world")], {
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.call([new HumanMessage("Print hello world")], {
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.call([new HumanMessage("Print hello world")], {
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.call([new HumanMessage("Print hello world")], {
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.call([system_message, user_message]);
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,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
+ });
@@ -32,6 +32,7 @@ test("Test timeout error thrown from SDK", async () => {
32
32
  await expect(async () => {
33
33
  const model = new OpenAIEmbeddings({
34
34
  timeout: 1,
35
+ maxRetries: 0,
35
36
  });
36
37
  await model.embedDocuments([
37
38
  "Hello world",
@@ -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.call("Print hello world");
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.call("What is my name");
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.call("Print hello world");
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.call("Print hello world", { stop: ["world"] });
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.call("Print hello world", {
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.call("Print hello world", {
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.call("Print hello world", {
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.call("Print hello world", {
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.call("Print hello world");
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.call("Print hello world", { stop: ["world"] });
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.call("Print hello world", {
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.call("Print hello world", {
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.call("Print hello world", {
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.call("Print hello world", {
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.call("Print hello world"),
84
- model.call("Print hello world"),
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.call("Print hello world");
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.call("Print hello world");
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.call("Print hello world");
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.call("Hello");
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.call("Print hello world");
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.18",
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.41",
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",