@langchain/openai 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -649,9 +649,15 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
649
649
  count += await this.getNumTokens(openAIMessage.additional_kwargs.function_call?.name);
650
650
  }
651
651
  if (openAIMessage.additional_kwargs.function_call?.arguments) {
652
- count += await this.getNumTokens(
653
- // Remove newlines and spaces
654
- JSON.stringify(JSON.parse(openAIMessage.additional_kwargs.function_call?.arguments)));
652
+ try {
653
+ count += await this.getNumTokens(
654
+ // Remove newlines and spaces
655
+ JSON.stringify(JSON.parse(openAIMessage.additional_kwargs.function_call?.arguments)));
656
+ }
657
+ catch (error) {
658
+ console.error("Error parsing function arguments", error, JSON.stringify(openAIMessage.additional_kwargs.function_call));
659
+ count += await this.getNumTokens(openAIMessage.additional_kwargs.function_call?.arguments);
660
+ }
655
661
  }
656
662
  totalCount += count;
657
663
  return count;
@@ -762,7 +768,7 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
762
768
  }
763
769
  }
764
770
  else {
765
- const functionName = name ?? "extract";
771
+ let functionName = name ?? "extract";
766
772
  // Is function calling
767
773
  if (isZodSchema(schema)) {
768
774
  const asJsonSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(schema);
@@ -791,15 +797,25 @@ class ChatOpenAI extends chat_models_1.BaseChatModel {
791
797
  });
792
798
  }
793
799
  else {
800
+ let openAIFunctionDefinition;
801
+ if (typeof schema.name === "string" &&
802
+ typeof schema.parameters === "object" &&
803
+ schema.parameters != null) {
804
+ openAIFunctionDefinition = schema;
805
+ functionName = schema.name;
806
+ }
807
+ else {
808
+ openAIFunctionDefinition = {
809
+ name: functionName,
810
+ description: schema.description ?? "",
811
+ parameters: schema,
812
+ };
813
+ }
794
814
  llm = this.bind({
795
815
  tools: [
796
816
  {
797
817
  type: "function",
798
- function: {
799
- name: functionName,
800
- description: schema.description,
801
- parameters: schema,
802
- },
818
+ function: openAIFunctionDefinition,
803
819
  },
804
820
  ],
805
821
  tool_choice: {
@@ -645,9 +645,15 @@ export class ChatOpenAI extends BaseChatModel {
645
645
  count += await this.getNumTokens(openAIMessage.additional_kwargs.function_call?.name);
646
646
  }
647
647
  if (openAIMessage.additional_kwargs.function_call?.arguments) {
648
- count += await this.getNumTokens(
649
- // Remove newlines and spaces
650
- JSON.stringify(JSON.parse(openAIMessage.additional_kwargs.function_call?.arguments)));
648
+ try {
649
+ count += await this.getNumTokens(
650
+ // Remove newlines and spaces
651
+ JSON.stringify(JSON.parse(openAIMessage.additional_kwargs.function_call?.arguments)));
652
+ }
653
+ catch (error) {
654
+ console.error("Error parsing function arguments", error, JSON.stringify(openAIMessage.additional_kwargs.function_call));
655
+ count += await this.getNumTokens(openAIMessage.additional_kwargs.function_call?.arguments);
656
+ }
651
657
  }
652
658
  totalCount += count;
653
659
  return count;
@@ -758,7 +764,7 @@ export class ChatOpenAI extends BaseChatModel {
758
764
  }
759
765
  }
760
766
  else {
761
- const functionName = name ?? "extract";
767
+ let functionName = name ?? "extract";
762
768
  // Is function calling
763
769
  if (isZodSchema(schema)) {
764
770
  const asJsonSchema = zodToJsonSchema(schema);
@@ -787,15 +793,25 @@ export class ChatOpenAI extends BaseChatModel {
787
793
  });
788
794
  }
789
795
  else {
796
+ let openAIFunctionDefinition;
797
+ if (typeof schema.name === "string" &&
798
+ typeof schema.parameters === "object" &&
799
+ schema.parameters != null) {
800
+ openAIFunctionDefinition = schema;
801
+ functionName = schema.name;
802
+ }
803
+ else {
804
+ openAIFunctionDefinition = {
805
+ name: functionName,
806
+ description: schema.description ?? "",
807
+ parameters: schema,
808
+ };
809
+ }
790
810
  llm = this.bind({
791
811
  tools: [
792
812
  {
793
813
  type: "function",
794
- function: {
795
- name: functionName,
796
- description: schema.description,
797
- parameters: schema,
798
- },
814
+ function: openAIFunctionDefinition,
799
815
  },
800
816
  ],
801
817
  tool_choice: {
@@ -521,6 +521,7 @@ test("Test ChatOpenAI token usage reporting for streaming function calls", async
521
521
  },
522
522
  ],
523
523
  }).bind({
524
+ seed: 42,
524
525
  functions: [extractionFunctionSchema],
525
526
  function_call: { name: "extractor" },
526
527
  });
@@ -543,6 +544,7 @@ test("Test ChatOpenAI token usage reporting for streaming function calls", async
543
544
  },
544
545
  ],
545
546
  }).bind({
547
+ seed: 42,
546
548
  functions: [extractionFunctionSchema],
547
549
  function_call: { name: "extractor" },
548
550
  });
@@ -87,6 +87,33 @@ test("withStructuredOutput JSON schema function calling", async () => {
87
87
  expect("number1" in result).toBe(true);
88
88
  expect("number2" in result).toBe(true);
89
89
  });
90
+ test("withStructuredOutput OpenAI function definition function calling", 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({
101
+ name: "calculator",
102
+ parameters: zodToJsonSchema(calculatorSchema),
103
+ });
104
+ const prompt = ChatPromptTemplate.fromMessages([
105
+ "system",
106
+ `You are VERY bad at math and must always use a calculator.`,
107
+ "human",
108
+ "Please help me!! What is 2 + 2?",
109
+ ]);
110
+ const chain = prompt.pipe(modelWithStructuredOutput);
111
+ const result = await chain.invoke({});
112
+ console.log(result);
113
+ expect("operation" in result).toBe(true);
114
+ expect("number1" in result).toBe(true);
115
+ expect("number2" in result).toBe(true);
116
+ });
90
117
  test("withStructuredOutput JSON schema JSON mode", async () => {
91
118
  const model = new ChatOpenAI({
92
119
  temperature: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/openai",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "OpenAI integrations for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {