From fa376c660f7797791c85ed5a883bf08ca75ac9af Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Wed, 31 Jul 2024 17:15:41 -0700 Subject: [PATCH 1/7] ci[patch]: Make notebook validation script handle default imports (#6302) * Make notebook validation script handle default imports * Format --- docs/core_docs/scripts/validate_notebook.ts | 28 ++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/core_docs/scripts/validate_notebook.ts b/docs/core_docs/scripts/validate_notebook.ts index 6f26d940be3a..776684ebc73f 100644 --- a/docs/core_docs/scripts/validate_notebook.ts +++ b/docs/core_docs/scripts/validate_notebook.ts @@ -15,15 +15,22 @@ export function extract(filepath: string) { // Deduplicate imports const importDeclarations = sourceFile.getImportDeclarations(); - const uniqueImports = new Map>(); + const uniqueImports = new Map< + string, + { default?: string; named: Set } + >(); importDeclarations.forEach((importDecl) => { const moduleSpecifier = importDecl.getModuleSpecifierValue(); if (!uniqueImports.has(moduleSpecifier)) { - uniqueImports.set(moduleSpecifier, new Set()); + uniqueImports.set(moduleSpecifier, { named: new Set() }); + } + const defaultImport = importDecl.getDefaultImport(); + if (defaultImport) { + uniqueImports.get(moduleSpecifier)!.default = defaultImport.getText(); } importDecl.getNamedImports().forEach((namedImport) => { - uniqueImports.get(moduleSpecifier)!.add(namedImport.getText()); + uniqueImports.get(moduleSpecifier)!.named.add(namedImport.getText()); }); }); @@ -31,12 +38,15 @@ export function extract(filepath: string) { importDeclarations.forEach((importDecl) => importDecl.remove()); // Add deduplicated imports at the top - uniqueImports.forEach((namedImports, moduleSpecifier) => { - sourceFile.addImportDeclaration({ - moduleSpecifier, - namedImports: Array.from(namedImports), - }); - }); + uniqueImports.forEach( + ({ default: defaultImport, named }, moduleSpecifier) => { + sourceFile.addImportDeclaration({ + moduleSpecifier, + defaultImport, + namedImports: Array.from(named), + }); + } + ); return sourceFile.getFullText(); } From 053de39b3c280c77e93103bf8635c48284370526 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Wed, 31 Jul 2024 22:13:13 -0700 Subject: [PATCH 2/7] core[patch]: Allow dynamic tools to be initialized with JSON schema (#6306) * Allow tools to be initialized with JSON schema * Fix lint * Add docstrings --- langchain-core/src/tools/index.ts | 74 +++++++++++---- langchain-core/src/tools/tests/tools.test.ts | 99 +++++++++++++++++++- 2 files changed, 152 insertions(+), 21 deletions(-) diff --git a/langchain-core/src/tools/index.ts b/langchain-core/src/tools/index.ts index c9e2c98402ae..a2c488e58bca 100644 --- a/langchain-core/src/tools/index.ts +++ b/langchain-core/src/tools/index.ts @@ -20,6 +20,7 @@ import { ZodObjectAny } from "../types/zod.js"; import { MessageContent } from "../messages/base.js"; import { AsyncLocalStorageProviderSingleton } from "../singletons/index.js"; import { _isToolCall, ToolInputParsingException } from "./utils.js"; +import { isZodSchema } from "../utils/types/is_zod_schema.js"; export { ToolInputParsingException }; @@ -319,16 +320,19 @@ export interface DynamicToolInput extends BaseDynamicToolInput { * Interface for the input parameters of the DynamicStructuredTool class. */ export interface DynamicStructuredToolInput< - T extends ZodObjectAny = ZodObjectAny + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends ZodObjectAny | Record = ZodObjectAny > extends BaseDynamicToolInput { func: ( input: BaseDynamicToolInput["responseFormat"] extends "content_and_artifact" ? ToolCall - : z.infer, + : T extends ZodObjectAny + ? z.infer + : T, runManager?: CallbackManagerForToolRun, config?: RunnableConfig ) => Promise; - schema: T; + schema: T extends ZodObjectAny ? T : T; } /** @@ -382,10 +386,14 @@ export class DynamicTool extends Tool { * description, designed to work with structured data. It extends the * StructuredTool class and overrides the _call method to execute the * provided function when the tool is called. + * + * Schema can be passed as Zod or JSON schema. The tool will not validate + * input if JSON schema is passed. */ export class DynamicStructuredTool< - T extends ZodObjectAny = ZodObjectAny -> extends StructuredTool { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends ZodObjectAny | Record = ZodObjectAny +> extends StructuredTool { static lc_name() { return "DynamicStructuredTool"; } @@ -396,7 +404,7 @@ export class DynamicStructuredTool< func: DynamicStructuredToolInput["func"]; - schema: T; + schema: T extends ZodObjectAny ? T : ZodObjectAny; constructor(fields: DynamicStructuredToolInput) { super(fields); @@ -404,14 +412,16 @@ export class DynamicStructuredTool< this.description = fields.description; this.func = fields.func; this.returnDirect = fields.returnDirect ?? this.returnDirect; - this.schema = fields.schema; + this.schema = ( + isZodSchema(fields.schema) ? fields.schema : z.object({}) + ) as T extends ZodObjectAny ? T : ZodObjectAny; } /** * @deprecated Use .invoke() instead. Will be removed in 0.3.0. */ async call( - arg: z.output | ToolCall, + arg: (T extends ZodObjectAny ? z.output : T) | ToolCall, configArg?: RunnableConfig | Callbacks, /** @deprecated */ tags?: string[] @@ -424,11 +434,12 @@ export class DynamicStructuredTool< } protected _call( - arg: z.output | ToolCall, + arg: (T extends ZodObjectAny ? z.output : T) | ToolCall, runManager?: CallbackManagerForToolRun, parentConfig?: RunnableConfig ): Promise { - return this.func(arg, runManager, parentConfig); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return this.func(arg as any, runManager, parentConfig); } } @@ -447,10 +458,16 @@ export abstract class BaseToolkit { /** * Parameters for the tool function. - * @template {ZodObjectAny | z.ZodString = ZodObjectAny} RunInput The input schema for the tool. Either any Zod object, or a Zod string. + * Schema can be provided as Zod or JSON schema. + * If you pass JSON schema, tool inputs will not be validated. + * @template {ZodObjectAny | z.ZodString | Record = ZodObjectAny} RunInput The input schema for the tool. Either any Zod object, a Zod string, or JSON schema. */ interface ToolWrapperParams< - RunInput extends ZodObjectAny | z.ZodString = ZodObjectAny + RunInput extends + | ZodObjectAny + | z.ZodString + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | Record = ZodObjectAny > extends ToolParams { /** * The name of the tool. If using with an LLM, this @@ -483,8 +500,11 @@ interface ToolWrapperParams< /** * Creates a new StructuredTool instance with the provided function, name, description, and schema. * + * Schema can be provided as Zod or JSON schema. + * If you pass JSON schema, tool inputs will not be validated. + * * @function - * @template {ZodObjectAny | z.ZodString = ZodObjectAny} T The input schema for the tool. Either any Zod object, or a Zod string. + * @template {ZodObjectAny | z.ZodString | Record = ZodObjectAny} T The input schema for the tool. Either any Zod object, a Zod string, or JSON schema instance. * * @param {RunnableFunc, ToolReturnType>} func - The function to invoke when the tool is called. * @param {ToolWrapperParams} fields - An object containing the following properties: @@ -494,18 +514,27 @@ interface ToolWrapperParams< * * @returns {DynamicStructuredTool} A new StructuredTool instance. */ -export function tool( +export function tool( func: RunnableFunc, ToolReturnType>, fields: ToolWrapperParams ): DynamicTool; -export function tool( +export function tool( func: RunnableFunc, ToolReturnType>, fields: ToolWrapperParams ): DynamicStructuredTool; -export function tool( - func: RunnableFunc, ToolReturnType>, +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function tool>( + func: RunnableFunc, + fields: ToolWrapperParams +): DynamicStructuredTool; + +export function tool< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends ZodObjectAny | z.ZodString | Record = ZodObjectAny +>( + func: RunnableFunc : T, ToolReturnType>, fields: ToolWrapperParams ): | DynamicStructuredTool @@ -518,7 +547,9 @@ export function tool( fields.description ?? fields.schema?.description ?? `${fields.name} tool`, - func, + // TS doesn't restrict the type here based on the guard above + // eslint-disable-next-line @typescript-eslint/no-explicit-any + func: func as any, }); } @@ -528,7 +559,8 @@ export function tool( return new DynamicStructuredTool({ ...fields, description, - schema: fields.schema as T extends ZodObjectAny ? T : ZodObjectAny, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema: fields.schema as any, // TODO: Consider moving into DynamicStructuredTool constructor func: async (input, runManager, config) => { return new Promise((resolve, reject) => { @@ -539,7 +571,9 @@ export function tool( childConfig, async () => { try { - resolve(func(input, childConfig)); + // TS doesn't restrict the type here based on the guard above + // eslint-disable-next-line @typescript-eslint/no-explicit-any + resolve(func(input as any, childConfig)); } catch (e) { reject(e); } diff --git a/langchain-core/src/tools/tests/tools.test.ts b/langchain-core/src/tools/tests/tools.test.ts index bf577a4a1dc9..4c38800b3489 100644 --- a/langchain-core/src/tools/tests/tools.test.ts +++ b/langchain-core/src/tools/tests/tools.test.ts @@ -1,6 +1,6 @@ import { test, expect } from "@jest/globals"; import { z } from "zod"; -import { tool } from "../index.js"; +import { DynamicStructuredTool, tool } from "../index.js"; import { ToolMessage } from "../../messages/tool.js"; test("Tool should error if responseFormat is content_and_artifact but the function doesn't return a tuple", async () => { @@ -115,3 +115,100 @@ test("Tool can accept single string input", async () => { const result = await stringTool.invoke("b"); expect(result).toBe("ba"); }); + +test("Tool declared with JSON schema", async () => { + const weatherSchema = { + type: "object", + properties: { + location: { + type: "string", + description: "A place", + }, + }, + required: ["location"], + }; + const weatherTool = tool( + (_) => { + return "Sunny"; + }, + { + name: "weather", + schema: weatherSchema, + } + ); + + const weatherTool2 = new DynamicStructuredTool({ + name: "weather", + description: "get the weather", + func: async (_) => { + return "Sunny"; + }, + schema: weatherSchema, + }); + // No validation on JSON schema tools + await weatherTool.invoke({ + somethingSilly: true, + }); + await weatherTool2.invoke({ + somethingSilly: true, + }); +}); + +test("Tool input typing is enforced", async () => { + const weatherSchema = z.object({ + location: z.string(), + }); + + const weatherTool = tool( + (_) => { + return "Sunny"; + }, + { + name: "weather", + schema: weatherSchema, + } + ); + + const weatherTool2 = new DynamicStructuredTool({ + name: "weather", + description: "get the weather", + func: async (_) => { + return "Sunny"; + }, + schema: weatherSchema, + }); + + const weatherTool3 = tool( + async (_) => { + return "Sunny"; + }, + { + name: "weather", + description: "get the weather", + schema: z.string(), + } + ); + + await expect(async () => { + await weatherTool.invoke({ + // @ts-expect-error Invalid argument + badval: "someval", + }); + }).rejects.toThrow(); + const res = await weatherTool.invoke({ + location: "somewhere", + }); + expect(res).toEqual("Sunny"); + await expect(async () => { + await weatherTool2.invoke({ + // @ts-expect-error Invalid argument + badval: "someval", + }); + }).rejects.toThrow(); + const res2 = await weatherTool2.invoke({ + location: "someval", + }); + expect(res2).toEqual("Sunny"); + const res3 = await weatherTool3.invoke("blah"); + expect(res3).toEqual("Sunny"); +}); From a643732fb5220e8079a3c43986d62a4bb8e8c96a Mon Sep 17 00:00:00 2001 From: Brace Sproul Date: Wed, 31 Jul 2024 22:13:57 -0700 Subject: [PATCH 3/7] docs[patch]: Fix .png badge bug and var naming (#6304) --- .../docs/integrations/chat/fireworks.ipynb | 10 +- .../docs/integrations/chat/mistral.ipynb | 115 +++++++++--------- 2 files changed, 67 insertions(+), 58 deletions(-) diff --git a/docs/core_docs/docs/integrations/chat/fireworks.ipynb b/docs/core_docs/docs/integrations/chat/fireworks.ipynb index e5276cd34c6b..9c2219315fca 100644 --- a/docs/core_docs/docs/integrations/chat/fireworks.ipynb +++ b/docs/core_docs/docs/integrations/chat/fireworks.ipynb @@ -3,10 +3,14 @@ { "cell_type": "raw", "id": "afaf8039", - "metadata": {}, + "metadata": { + "vscode": { + "languageId": "raw" + } + }, "source": [ "---\n", - "sidebar_label: ChatFireworks\n", + "sidebar_label: Fireworks\n", "---" ] }, @@ -24,7 +28,7 @@ "\n", "| Class | Package | Local | Serializable | [PY support](https:/python.langchain.com/v0.2/docs/integrations/chat/fireworks) | Package downloads | Package latest |\n", "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| [ChatFireworks](https://api.js.langchain.com/classes/langchain_community_chat_models_fireworks.ChatFireworks.html) | [@langchain/community](https://api.js.langchain.com/modules/langchain_community_chat_models_fireworks.html) | ❌ | ✅ | ✅ | ![NPM - Downloads](https://img.shields.io/npm/dm/@langchain/community?style=flat-square&label=%20) | ![NPM - Version](https://img.shields.io/npm/v/@langchain/community?style=flat-square&label=%20) |\n", + "| [ChatFireworks](https://api.js.langchain.com/classes/langchain_community_chat_models_fireworks.ChatFireworks.html) | [@langchain/community](https://api.js.langchain.com/modules/langchain_community_chat_models_fireworks.html) | ❌ | ✅ | ✅ | ![NPM - Downloads](https://img.shields.io/npm/dm/@langchain/community?style=flat-square&label=%20&) | ![NPM - Version](https://img.shields.io/npm/v/@langchain/community?style=flat-square&label=%20&) |\n", "\n", "### Model features\n", "| [Tool calling](/docs/how_to/tool_calling) | [Structured output](/docs/how_to/structured_output/) | JSON mode | [Image input](/docs/how_to/multimodal_inputs/) | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n", diff --git a/docs/core_docs/docs/integrations/chat/mistral.ipynb b/docs/core_docs/docs/integrations/chat/mistral.ipynb index f308e0c1d768..047ec3c4e1ad 100644 --- a/docs/core_docs/docs/integrations/chat/mistral.ipynb +++ b/docs/core_docs/docs/integrations/chat/mistral.ipynb @@ -3,10 +3,14 @@ { "cell_type": "raw", "id": "afaf8039", - "metadata": {}, + "metadata": { + "vscode": { + "languageId": "raw" + } + }, "source": [ "---\n", - "sidebar_label: ChatMistralAI\n", + "sidebar_label: MistralAI\n", "---" ] }, @@ -24,7 +28,7 @@ "\n", "| Class | Package | Local | Serializable | [PY support](https:/python.langchain.com/v0.2/docs/integrations/chat/mistralai) | Package downloads | Package latest |\n", "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| [ChatMistralAI](https://api.js.langchain.com/classes/langchain_mistralai.ChatMistralAI.html) | [@langchain/mistralai](https://api.js.langchain.com/modules/langchain_mistralai.html) | ❌ | ❌ | ✅ | ![NPM - Downloads](https://img.shields.io/npm/dm/@langchain/mistralai?style=flat-square&label=%20) | ![NPM - Version](https://img.shields.io/npm/v/@langchain/mistralai?style=flat-square&label=%20) |\n", + "| [ChatMistralAI](https://api.js.langchain.com/classes/langchain_mistralai.ChatMistralAI.html) | [@langchain/mistralai](https://api.js.langchain.com/modules/langchain_mistralai.html) | ❌ | ❌ | ✅ | ![NPM - Downloads](https://img.shields.io/npm/dm/@langchain/mistralai?style=flat-square&label=%20&) | ![NPM - Version](https://img.shields.io/npm/v/@langchain/mistralai?style=flat-square&label=%20&) |\n", "\n", "### Model features\n", "| [Tool calling](/docs/how_to/tool_calling) | [Structured output](/docs/how_to/structured_output/) | JSON mode | [Image input](/docs/how_to/multimodal_inputs/) | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n", @@ -250,7 +254,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 1, "id": "98d9034c", "metadata": {}, "outputs": [ @@ -263,7 +267,7 @@ " name: 'calculator',\n", " args: { operation: 'add', number1: 2, number2: 2 },\n", " type: 'tool_call',\n", - " id: '2HFfjvCvo'\n", + " id: 'Tn8X3UCSP'\n", " }\n", "]\n" ] @@ -275,7 +279,7 @@ "import { z } from \"zod\";\n", "import { tool } from \"@langchain/core/tools\";\n", "\n", - "const calculatorSchema2 = z.object({\n", + "const calculatorSchema = z.object({\n", " operation: z\n", " .enum([\"add\", \"subtract\", \"multiply\", \"divide\"])\n", " .describe(\"The type of operation to execute.\"),\n", @@ -283,24 +287,23 @@ " number2: z.number().describe(\"The second number to operate on.\"),\n", "});\n", "\n", - "const calculatorTool2 = tool((input) => {\n", + "const calculatorTool = tool((input) => {\n", " return JSON.stringify(input);\n", "}, {\n", " name: \"calculator\",\n", " description: \"A simple calculator tool\",\n", - " schema: calculatorSchema2,\n", + " schema: calculatorSchema,\n", "});\n", "\n", - "const llm2 = new ChatMistralAI({\n", + "// Bind the tool to the model\n", + "const modelWithTool = new ChatMistralAI({\n", " model: \"mistral-large-latest\",\n", + "}).bind({\n", + " tools: [calculatorTool],\n", "});\n", "\n", - "// Bind the tool to the model\n", - "const modelWithTool2 = llm2.bind({\n", - " tools: [calculatorTool2],\n", - "});\n", "\n", - "const prompt2 = ChatPromptTemplate.fromMessages([\n", + "const calcToolPrompt = ChatPromptTemplate.fromMessages([\n", " [\n", " \"system\",\n", " \"You are a helpful assistant who always needs to use a calculator.\",\n", @@ -309,12 +312,12 @@ "]);\n", "\n", "// Chain your prompt, model, and output parser together\n", - "const chain2 = prompt2.pipe(modelWithTool2);\n", + "const chainWithCalcTool = calcToolPrompt.pipe(modelWithTool);\n", "\n", - "const response2 = await chain2.invoke({\n", + "const calcToolRes = await chainWithCalcTool.invoke({\n", " input: \"What is 2 + 2?\",\n", "});\n", - "console.log(response2.tool_calls);" + "console.log(calcToolRes.tool_calls);" ] }, { @@ -337,7 +340,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "id": "a8638d82", "metadata": {}, "outputs": [ @@ -354,7 +357,7 @@ "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", "import { z } from \"zod\";\n", "\n", - "const calculatorSchema3 = z\n", + "const calculatorSchemaForWSO = z\n", " .object({\n", " operation: z\n", " .enum([\"add\", \"subtract\", \"multiply\", \"divide\"])\n", @@ -364,14 +367,16 @@ " })\n", " .describe(\"A simple calculator tool\");\n", "\n", - "const llm3 = new ChatMistralAI({\n", + "const llmForWSO = new ChatMistralAI({\n", " model: \"mistral-large-latest\",\n", - "});\n", + "})\n", "\n", "// Pass the schema and tool name to the withStructuredOutput method\n", - "const modelWithTool3 = llm3.withStructuredOutput(calculatorSchema3);\n", + "const modelWithStructuredOutput = llmForWSO.withStructuredOutput(calculatorSchemaForWSO, {\n", + " name: \"calculator\",\n", + "});\n", "\n", - "const prompt3 = ChatPromptTemplate.fromMessages([\n", + "const promptForWSO = ChatPromptTemplate.fromMessages([\n", " [\n", " \"system\",\n", " \"You are a helpful assistant who always needs to use a calculator.\",\n", @@ -380,12 +385,12 @@ "]);\n", "\n", "// Chain your prompt and model together\n", - "const chain3 = prompt3.pipe(modelWithTool3);\n", + "const chainWSO = promptForWSO.pipe(modelWithStructuredOutput);\n", "\n", - "const response3 = await chain3.invoke({\n", + "const responseWSO = await chainWSO.invoke({\n", " input: \"What is 2 + 2?\",\n", "});\n", - "console.log(response3);" + "console.log(responseWSO);" ] }, { @@ -398,7 +403,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "id": "9786b41a", "metadata": {}, "outputs": [ @@ -416,14 +421,14 @@ " name: 'calculator',\n", " args: { operation: 'add', number1: 2, number2: 2 },\n", " type: 'tool_call',\n", - " id: 'qVxKofNLR'\n", + " id: 'w48T6Nc3d'\n", " }\n", " ],\n", " invalid_tool_calls: [],\n", " additional_kwargs: {\n", " tool_calls: [\n", " {\n", - " id: 'qVxKofNLR',\n", + " id: 'w48T6Nc3d',\n", " function: {\n", " name: 'calculator',\n", " arguments: '{\"operation\": \"add\", \"number1\": 2, \"number2\": 2}'\n", @@ -441,7 +446,7 @@ " additional_kwargs: {\n", " tool_calls: [\n", " {\n", - " id: 'qVxKofNLR',\n", + " id: 'w48T6Nc3d',\n", " function: {\n", " name: 'calculator',\n", " arguments: '{\"operation\": \"add\", \"number1\": 2, \"number2\": 2}'\n", @@ -460,7 +465,7 @@ " name: 'calculator',\n", " args: { operation: 'add', number1: 2, number2: 2 },\n", " type: 'tool_call',\n", - " id: 'qVxKofNLR'\n", + " id: 'w48T6Nc3d'\n", " }\n", " ],\n", " invalid_tool_calls: [],\n", @@ -472,16 +477,16 @@ } ], "source": [ - "const includeRawModel3 = llm3.withStructuredOutput(calculatorSchema3, {\n", + "const includeRawModel = llmForWSO.withStructuredOutput(calculatorSchemaForWSO, {\n", " name: \"calculator\",\n", " includeRaw: true,\n", "});\n", - "const includeRawChain3 = prompt3.pipe(includeRawModel3);\n", + "const includeRawChain = promptForWSO.pipe(includeRawModel);\n", "\n", - "const includeRawResponse3 = await includeRawChain3.invoke({\n", + "const includeRawResponse = await includeRawChain.invoke({\n", " input: \"What is 2 + 2?\",\n", "});\n", - "console.dir(includeRawResponse3, { depth: null });" + "console.dir(includeRawResponse, { depth: null });" ] }, { @@ -494,7 +499,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "id": "9f1dc9bd", "metadata": {}, "outputs": [ @@ -510,7 +515,7 @@ "import { ChatMistralAI } from \"@langchain/mistralai\";\n", "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", "\n", - "const calculatorJsonSchema4 = {\n", + "const calculatorJsonSchema = {\n", " type: \"object\",\n", " properties: {\n", " operation: {\n", @@ -528,14 +533,14 @@ " description: \"A simple calculator tool\",\n", "};\n", "\n", - "const llm4 = new ChatMistralAI({\n", + "const llmForJsonSchema = new ChatMistralAI({\n", " model: \"mistral-large-latest\",\n", "});\n", "\n", "// Pass the schema and tool name to the withStructuredOutput method\n", - "const modelWithTool4 = llm4.withStructuredOutput(calculatorJsonSchema4);\n", + "const modelWithJsonSchemaTool = llmForJsonSchema.withStructuredOutput(calculatorJsonSchema);\n", "\n", - "const prompt4 = ChatPromptTemplate.fromMessages([\n", + "const promptForJsonSchema = ChatPromptTemplate.fromMessages([\n", " [\n", " \"system\",\n", " \"You are a helpful assistant who always needs to use a calculator.\",\n", @@ -544,12 +549,12 @@ "]);\n", "\n", "// Chain your prompt and model together\n", - "const chain4 = prompt4.pipe(modelWithTool4);\n", + "const chainWithJsonSchema = promptForJsonSchema.pipe(modelWithJsonSchemaTool);\n", "\n", - "const response4 = await chain4.invoke({\n", + "const responseFromJsonSchema = await chainWithJsonSchema.invoke({\n", " input: \"What is 2 + 2?\",\n", "});\n", - "console.log(response4);\n" + "console.log(responseFromJsonSchema);\n" ] }, { @@ -565,7 +570,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 6, "id": "76bd0061", "metadata": {}, "outputs": [ @@ -573,7 +578,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "The weather in Paris is 28 °C.\n" + "It's 28 °C in Paris.\n" ] } ], @@ -585,13 +590,13 @@ "\n", "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", "\n", - "const llm5 = new ChatMistralAI({\n", + "const llmForAgent = new ChatMistralAI({\n", " temperature: 0,\n", " model: \"mistral-large-latest\",\n", "});\n", "\n", "// Prompt template must have \"input\" and \"agent_scratchpad input variables\"\n", - "const prompt5 = ChatPromptTemplate.fromMessages([\n", + "const agentPrompt = ChatPromptTemplate.fromMessages([\n", " [\"system\", \"You are a helpful assistant\"],\n", " [\"placeholder\", \"{chat_history}\"],\n", " [\"human\", \"{input}\"],\n", @@ -599,7 +604,7 @@ "]);\n", "\n", "// Mocked tool\n", - "const currentWeatherTool5 = tool(async () => \"28 °C\", {\n", + "const currentWeatherToolForAgent = tool(async () => \"28 °C\", {\n", " name: \"get_current_weather\",\n", " description: \"Get the current weather in a given location\",\n", " schema: z.object({\n", @@ -608,20 +613,20 @@ "});\n", "\n", "const agent = createToolCallingAgent({\n", - " llm: llm5,\n", - " tools: [currentWeatherTool5],\n", - " prompt: prompt5,\n", + " llm: llmForAgent,\n", + " tools: [currentWeatherToolForAgent],\n", + " prompt: agentPrompt,\n", "});\n", "\n", "const agentExecutor = new AgentExecutor({\n", " agent,\n", - " tools: [currentWeatherTool5],\n", + " tools: [currentWeatherToolForAgent],\n", "});\n", "\n", - "const input = \"What's the weather like in Paris?\";\n", - "const { output } = await agentExecutor.invoke({ input });\n", + "const agentInput = \"What's the weather like in Paris?\";\n", + "const agentRes = await agentExecutor.invoke({ input: agentInput });\n", "\n", - "console.log(output);\n" + "console.log(agentRes.output);\n" ] }, { From 31ee0e367dcbdf27af70a9dd7da31d555a617862 Mon Sep 17 00:00:00 2001 From: Tony Qu <18809892579qu@gmail.com> Date: Thu, 1 Aug 2024 14:19:28 +0800 Subject: [PATCH 4/7] Fix: Change sqlite to SQL in query checker prompt (#6307) In the `sqlAgent`, the `query-checker` step currently references `sqlite` specifically in the prompt, which is incorrect since the `sqlAgent` can interact with multiple types of databases. To make this prompt more accurate and applicable to various SQL databases, I have replaced `sqlite` with `SQL`. --- langchain/src/tools/sql.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langchain/src/tools/sql.ts b/langchain/src/tools/sql.ts index 09584fe980e3..6a139af3d5c2 100644 --- a/langchain/src/tools/sql.ts +++ b/langchain/src/tools/sql.ts @@ -156,7 +156,7 @@ export class QueryCheckerTool extends Tool { template = ` {query} -Double check the sqlite query above for common mistakes, including: +Double check the SQL query above for common mistakes, including: - Using NOT IN with NULL values - Using UNION when UNION ALL should have been used - Using BETWEEN for exclusive ranges From 6282b424c15f6b9abc63c4b739904cb3d3cbb7d0 Mon Sep 17 00:00:00 2001 From: Brace Sproul Date: Thu, 1 Aug 2024 09:57:53 -0700 Subject: [PATCH 5/7] docs[minor]: Update ChatAzureOpenAI integration docs (#6285) * docs[minor]: Update Azure integration docs * fix npm2yarn * update .png badge bug and improve naming * fix py bug --- .../docs/integrations/chat/azure.ipynb | 399 ++++++++++++++++++ .../docs/integrations/chat/azure.mdx | 116 ----- 2 files changed, 399 insertions(+), 116 deletions(-) create mode 100644 docs/core_docs/docs/integrations/chat/azure.ipynb delete mode 100644 docs/core_docs/docs/integrations/chat/azure.mdx diff --git a/docs/core_docs/docs/integrations/chat/azure.ipynb b/docs/core_docs/docs/integrations/chat/azure.ipynb new file mode 100644 index 000000000000..dbae00d112e2 --- /dev/null +++ b/docs/core_docs/docs/integrations/chat/azure.ipynb @@ -0,0 +1,399 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "afaf8039", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "---\n", + "sidebar_label: Azure OpenAI\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "e49f1e0d", + "metadata": {}, + "source": [ + "# AzureChatOpenAI\n", + "\n", + "This will help you getting started with AzureChatOpenAI [chat models](/docs/concepts/#chat-models). For detailed documentation of all AzureChatOpenAI features and configurations head to the [API reference](https://api.js.langchain.com/classes/langchain_openai.AzureChatOpenAI.html).\n", + "\n", + "## Overview\n", + "### Integration details\n", + "\n", + "| Class | Package | Local | Serializable | [PY support](https://python.langchain.com/v0.2/docs/integrations/chat/azure) | Package downloads | Package latest |\n", + "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", + "| [AzureChatOpenAI](https://api.js.langchain.com/classes/langchain_openai.AzureChatOpenAI.html) | [@langchain/openai](https://api.js.langchain.com/modules/langchain_openai.html) | ❌ | ✅ | ✅ | ![NPM - Downloads](https://img.shields.io/npm/dm/@langchain/openai?style=flat-square&label=%20&) | ![NPM - Version](https://img.shields.io/npm/v/@langchain/openai?style=flat-square&label=%20&) |\n", + "\n", + "### Model features\n", + "| [Tool calling](/docs/how_to/tool_calling) | [Structured output](/docs/how_to/structured_output/) | JSON mode | [Image input](/docs/how_to/multimodal_inputs/) | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n", + "| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n", + "| ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | \n", + "\n", + "## Setup\n", + "\n", + "[Azure OpenAI](https://azure.microsoft.com/products/ai-services/openai-service/) is a cloud service to help you quickly develop generative AI experiences with a diverse set of prebuilt and curated models from OpenAI, Meta and beyond.\n", + "\n", + "LangChain.js supports integration with [Azure OpenAI](https://azure.microsoft.com/products/ai-services/openai-service/) using the new Azure integration in the [OpenAI SDK](https://github.com/openai/openai-node).\n", + "\n", + "You can learn more about Azure OpenAI and its difference with the OpenAI API on [this page](https://learn.microsoft.com/azure/ai-services/openai/overview).\n", + "\n", + "### Credentials\n", + "\n", + "If you don't have an Azure account, you can [create a free account](https://azure.microsoft.com/free/) to get started.\n", + "\n", + "You'll also need to have an Azure OpenAI instance deployed. You can deploy a version on Azure Portal following [this guide](https://learn.microsoft.com/azure/ai-services/openai/how-to/create-resource?pivots=web-portal).\n", + "\n", + "Once you have your instance running, make sure you have the name of your instance and key. You can find the key in the Azure Portal, under the \"Keys and Endpoint\" section of your instance. Then, if using Node.js, you can set your credentials as environment variables:\n", + "\n", + "```bash\n", + "AZURE_OPENAI_API_INSTANCE_NAME=\n", + "AZURE_OPENAI_API_DEPLOYMENT_NAME=\n", + "AZURE_OPENAI_API_KEY=\n", + "AZURE_OPENAI_API_VERSION=\"2024-02-01\"\n", + "```\n", + "\n", + "If you want to get automated tracing of your model calls you can also set your [LangSmith](https://docs.smith.langchain.com/) API key by uncommenting below:\n", + "\n", + "```bash\n", + "# export LANGCHAIN_TRACING_V2=\"true\"\n", + "# export LANGCHAIN_API_KEY=\"your-api-key\"\n", + "```\n", + "\n", + "### Installation\n", + "\n", + "The LangChain AzureChatOpenAI integration lives in the `@langchain/openai` package:\n", + "\n", + "```{=mdx}\n", + "\n", + "import IntegrationInstallTooltip from \"@mdx_components/integration_install_tooltip.mdx\";\n", + "import Npm2Yarn from \"@theme/Npm2Yarn\";\n", + "\n", + "\n", + "\n", + "\n", + " @langchain/openai\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "a38cde65-254d-4219-a441-068766c0d4b5", + "metadata": {}, + "source": [ + "## Instantiation\n", + "\n", + "Now we can instantiate our model object and generate chat completions:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cb09c344-1836-4e0c-acf8-11d13ac1dbae", + "metadata": {}, + "outputs": [], + "source": [ + "import { AzureChatOpenAI } from \"@langchain/openai\" \n", + "\n", + "const llm = new AzureChatOpenAI({\n", + " model: \"gpt-4o\",\n", + " temperature: 0,\n", + " maxTokens: undefined,\n", + " maxRetries: 2,\n", + " azureOpenAIApiKey: process.env.AZURE_OPENAI_API_KEY, // In Node.js defaults to process.env.AZURE_OPENAI_API_KEY\n", + " azureOpenAIApiInstanceName: process.env.AZURE_OPENAI_API_INSTANCE_NAME, // In Node.js defaults to process.env.AZURE_OPENAI_API_INSTANCE_NAME\n", + " azureOpenAIApiDeploymentName: process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME, // In Node.js defaults to process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME\n", + " azureOpenAIApiVersion: process.env.AZURE_OPENAI_API_VERSION, // In Node.js defaults to process.env.AZURE_OPENAI_API_VERSION\n", + "})" + ] + }, + { + "cell_type": "markdown", + "id": "2b4f3e15", + "metadata": {}, + "source": [ + "## Invocation" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "62e0dbc3", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "AIMessage {\n", + " \"id\": \"chatcmpl-9qrWKByvVrzWMxSn8joRZAklHoB32\",\n", + " \"content\": \"J'adore la programmation.\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {\n", + " \"tokenUsage\": {\n", + " \"completionTokens\": 8,\n", + " \"promptTokens\": 31,\n", + " \"totalTokens\": 39\n", + " },\n", + " \"finish_reason\": \"stop\"\n", + " },\n", + " \"tool_calls\": [],\n", + " \"invalid_tool_calls\": [],\n", + " \"usage_metadata\": {\n", + " \"input_tokens\": 31,\n", + " \"output_tokens\": 8,\n", + " \"total_tokens\": 39\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "const aiMsg = await llm.invoke([\n", + " [\n", + " \"system\",\n", + " \"You are a helpful assistant that translates English to French. Translate the user sentence.\",\n", + " ],\n", + " [\"human\", \"I love programming.\"],\n", + "])\n", + "aiMsg" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d86145b3-bfef-46e8-b227-4dda5c9c2705", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "J'adore la programmation.\n" + ] + } + ], + "source": [ + "console.log(aiMsg.content)" + ] + }, + { + "cell_type": "markdown", + "id": "18e2bfc0-7e78-4528-a73f-499ac150dca8", + "metadata": {}, + "source": [ + "## Chaining\n", + "\n", + "We can [chain](/docs/how_to/sequence/) our model with a prompt template like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "e197d1d7-a070-4c96-9f8a-a0e86d046e0b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "AIMessage {\n", + " \"id\": \"chatcmpl-9qrWR7WiNjZ3leSG4Wd77cnKEVivv\",\n", + " \"content\": \"Ich liebe das Programmieren.\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {\n", + " \"tokenUsage\": {\n", + " \"completionTokens\": 6,\n", + " \"promptTokens\": 26,\n", + " \"totalTokens\": 32\n", + " },\n", + " \"finish_reason\": \"stop\"\n", + " },\n", + " \"tool_calls\": [],\n", + " \"invalid_tool_calls\": [],\n", + " \"usage_metadata\": {\n", + " \"input_tokens\": 26,\n", + " \"output_tokens\": 6,\n", + " \"total_tokens\": 32\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "import { ChatPromptTemplate } from \"@langchain/core/prompts\"\n", + "\n", + "const prompt = ChatPromptTemplate.fromMessages(\n", + " [\n", + " [\n", + " \"system\",\n", + " \"You are a helpful assistant that translates {input_language} to {output_language}.\",\n", + " ],\n", + " [\"human\", \"{input}\"],\n", + " ]\n", + ")\n", + "\n", + "const chain = prompt.pipe(llm);\n", + "await chain.invoke(\n", + " {\n", + " input_language: \"English\",\n", + " output_language: \"German\",\n", + " input: \"I love programming.\",\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d1ee55bc-ffc8-4cfa-801c-993953a08cfd", + "metadata": {}, + "source": [ + "## Using Azure Managed Identity\n", + "\n", + "If you're using Azure Managed Identity, you can configure the credentials like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "d7f47b2a", + "metadata": {}, + "outputs": [], + "source": [ + "import {\n", + " DefaultAzureCredential,\n", + " getBearerTokenProvider,\n", + "} from \"@azure/identity\";\n", + "import { AzureChatOpenAI } from \"@langchain/openai\";\n", + "\n", + "const credentials = new DefaultAzureCredential();\n", + "const azureADTokenProvider = getBearerTokenProvider(\n", + " credentials,\n", + " \"https://cognitiveservices.azure.com/.default\"\n", + ");\n", + "\n", + "const llmWithManagedIdentity = new AzureChatOpenAI({\n", + " azureADTokenProvider,\n", + " azureOpenAIApiInstanceName: \"\",\n", + " azureOpenAIApiDeploymentName: \"\",\n", + " azureOpenAIApiVersion: \"\",\n", + "});" + ] + }, + { + "cell_type": "markdown", + "id": "6a889856", + "metadata": {}, + "source": [ + "## Using a different domain\n", + "\n", + "If your instance is hosted under a domain other than the default `openai.azure.com`, you'll need to use the alternate `AZURE_OPENAI_BASE_PATH` environment variable.\n", + "For example, here's how you would connect to the domain `https://westeurope.api.microsoft.com/openai/deployments/{DEPLOYMENT_NAME}`:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "ace7f876", + "metadata": {}, + "outputs": [], + "source": [ + "import { AzureChatOpenAI } from \"@langchain/openai\";\n", + "\n", + "const llmWithDifferentDomain = new AzureChatOpenAI({\n", + " temperature: 0.9,\n", + " azureOpenAIApiKey: \"\", // In Node.js defaults to process.env.AZURE_OPENAI_API_KEY\n", + " azureOpenAIApiDeploymentName: \"\", // In Node.js defaults to process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME\n", + " azureOpenAIApiVersion: \"\", // In Node.js defaults to process.env.AZURE_OPENAI_API_VERSION\n", + " azureOpenAIBasePath:\n", + " \"https://westeurope.api.microsoft.com/openai/deployments\", // In Node.js defaults to process.env.AZURE_OPENAI_BASE_PATH\n", + "});\n" + ] + }, + { + "cell_type": "markdown", + "id": "0ac0310c", + "metadata": {}, + "source": [ + "## Migration from Azure OpenAI SDK\n", + "\n", + "If you are using the deprecated Azure OpenAI SDK with the `@langchain/azure-openai` package, you can update your code to use the new Azure integration following these steps:\n", + "\n", + "1. Install the new `@langchain/openai` package and remove the previous `@langchain/azure-openai` package:\n", + "\n", + "```{=mdx}\n", + "\n", + "\n", + " @langchain/openai\n", + "\n", + "\n", + "```\n", + "\n", + "```bash\n", + "npm uninstall @langchain/azure-openai\n", + "```\n", + "\n", + " \n", + "2. Update your imports to use the new `AzureChatOpenAI` class from the `@langchain/openai` package:\n", + " ```typescript\n", + " import { AzureChatOpenAI } from \"@langchain/openai\";\n", + " ```\n", + "3. Update your code to use the new `AzureChatOpenAI` class and pass the required parameters:\n", + "\n", + " ```typescript\n", + " const model = new AzureChatOpenAI({\n", + " azureOpenAIApiKey: \"\",\n", + " azureOpenAIApiInstanceName: \"\",\n", + " azureOpenAIApiDeploymentName: \"\",\n", + " azureOpenAIApiVersion: \"\",\n", + " });\n", + " ```\n", + "\n", + " Notice that the constructor now requires the `azureOpenAIApiInstanceName` parameter instead of the `azureOpenAIEndpoint` parameter, and adds the `azureOpenAIApiVersion` parameter to specify the API version.\n", + "\n", + " - If you were using Azure Managed Identity, you now need to use the `azureADTokenProvider` parameter to the constructor instead of `credentials`, see the [Azure Managed Identity](#using-azure-managed-identity) section for more details.\n", + "\n", + " - If you were using environment variables, you now have to set the `AZURE_OPENAI_API_INSTANCE_NAME` environment variable instead of `AZURE_OPENAI_API_ENDPOINT`, and add the `AZURE_OPENAI_API_VERSION` environment variable to specify the API version.\n" + ] + }, + { + "cell_type": "markdown", + "id": "3a5bb5ca-c3ae-4a58-be67-2cd18574b9a3", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all AzureChatOpenAI features and configurations head to the API reference: https://api.js.langchain.com/classes/langchain_openai.AzureChatOpenAI.html" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "TypeScript", + "language": "typescript", + "name": "tslab" + }, + "language_info": { + "codemirror_mode": { + "mode": "typescript", + "name": "javascript", + "typescript": true + }, + "file_extension": ".ts", + "mimetype": "text/typescript", + "name": "typescript", + "version": "3.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/core_docs/docs/integrations/chat/azure.mdx b/docs/core_docs/docs/integrations/chat/azure.mdx deleted file mode 100644 index 912bd1e72fdd..000000000000 --- a/docs/core_docs/docs/integrations/chat/azure.mdx +++ /dev/null @@ -1,116 +0,0 @@ ---- -sidebar_label: Azure OpenAI -keywords: [AzureChatOpenAI] ---- - -import CodeBlock from "@theme/CodeBlock"; - -# Azure OpenAI - -[Azure OpenAI](https://azure.microsoft.com/products/ai-services/openai-service/) is a cloud service to help you quickly develop generative AI experiences with a diverse set of prebuilt and curated models from OpenAI, Meta and beyond. - -LangChain.js supports integration with [Azure OpenAI](https://azure.microsoft.com/products/ai-services/openai-service/) using the new Azure integration in the [OpenAI SDK](https://github.com/openai/openai-node). - -You can learn more about Azure OpenAI and its difference with the OpenAI API on [this page](https://learn.microsoft.com/azure/ai-services/openai/overview). If you don't have an Azure account, you can [create a free account](https://azure.microsoft.com/free/) to get started. - -:::info - -Previously, LangChain.js supported integration with Azure OpenAI using the dedicated [Azure OpenAI SDK](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/openai/openai). This SDK is now deprecated in favor of the new Azure integration in the OpenAI SDK, which allows to access the latest OpenAI models and features the same day they are released, and allows seemless transition between the OpenAI API and Azure OpenAI. - -If you are using Azure OpenAI with the deprecated SDK, see the [migration guide](#migration-from-azure-openai-sdk) to update to the new API. - -::: - -## Setup - -You'll first need to install the [`@langchain/openai`](https://www.npmjs.com/package/@langchain/openai) package: - -import IntegrationInstallTooltip from "@mdx_components/integration_install_tooltip.mdx"; - - - -```bash npm2yarn -npm install -S @langchain/openai -``` - -You'll also need to have an Azure OpenAI instance deployed. You can deploy a version on Azure Portal following [this guide](https://learn.microsoft.com/azure/ai-services/openai/how-to/create-resource?pivots=web-portal). - -Once you have your instance running, make sure you have the name of your instance and key. You can find the key in the Azure Portal, under the "Keys and Endpoint" section of your instance. - -If you're using Node.js, you can define the following environment variables to use the service: - -```bash -AZURE_OPENAI_API_INSTANCE_NAME= -AZURE_OPENAI_API_DEPLOYMENT_NAME= -AZURE_OPENAI_API_KEY= -AZURE_OPENAI_API_VERSION="2024-02-01" -``` - -Alternatively, you can pass the values directly to the `AzureOpenAI` constructor: - -import AzureOpenAI from "@examples/models/chat/integration_azure_openai.ts"; - -import UnifiedModelParamsTooltip from "@mdx_components/unified_model_params_tooltip.mdx"; - - - -{AzureOpenAI} - -:::info - -You can find the list of supported API versions in the [Azure OpenAI documentation](https://learn.microsoft.com/azure/ai-services/openai/reference). - -::: - -### Using Azure Managed Identity - -If you're using Azure Managed Identity, you can configure the credentials like this: - -import AzureOpenAIManagedIdentity from "@examples/models/chat/integration_azure_openai_managed_identity.ts"; - -{AzureOpenAIManagedIdentity} - -### Using a different domain - -If your instance is hosted under a domain other than the default `openai.azure.com`, you'll need to use the alternate `AZURE_OPENAI_BASE_PATH` environment variable. -For example, here's how you would connect to the domain `https://westeurope.api.microsoft.com/openai/deployments/{DEPLOYMENT_NAME}`: - -import AzureOpenAIBasePath from "@examples/models/chat/integration_azure_openai_base_path.ts"; - -{AzureOpenAIBasePath} - -## Usage example - -import Example from "@examples/models/chat/integration_azure_chat_openai.ts"; - -{Example} - -## Migration from Azure OpenAI SDK - -If you are using the deprecated Azure OpenAI SDK with the `@langchain/azure-openai` package, you can update your code to use the new Azure integration following these steps: - -1. Install the new `@langchain/openai` package and remove the previous `@langchain/azure-openai` package: - ```bash npm2yarn - npm install @langchain/openai - npm uninstall @langchain/azure-openai - ``` -2. Update your imports to use the new `AzureChatOpenAI` class from the `@langchain/openai` package: - ```typescript - import { AzureChatOpenAI } from "@langchain/openai"; - ``` -3. Update your code to use the new `AzureChatOpenAI` class and pass the required parameters: - - ```typescript - const model = new AzureChatOpenAI({ - azureOpenAIApiKey: "", - azureOpenAIApiInstanceName: "", - azureOpenAIApiDeploymentName: "", - azureOpenAIApiVersion: "", - }); - ``` - - Notice that the constructor now requires the `azureOpenAIApiInstanceName` parameter instead of the `azureOpenAIEndpoint` parameter, and adds the `azureOpenAIApiVersion` parameter to specify the API version. - - - If you were using Azure Managed Identity, you now need to use the `azureADTokenProvider` parameter to the constructor instead of `credentials`, see the [Azure Managed Identity](#using-azure-managed-identity) section for more details. - - - If you were using environment variables, you now have to set the `AZURE_OPENAI_API_INSTANCE_NAME` environment variable instead of `AZURE_OPENAI_API_ENDPOINT`, and add the `AZURE_OPENAI_API_VERSION` environment variable to specify the API version. From 96fe56ab6cfd693cb7d8ac6485e5addaecb20e9b Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Thu, 1 Aug 2024 10:12:12 -0700 Subject: [PATCH 6/7] Fix types (#6313) --- libs/langchain-community/src/llms/layerup_security.ts | 6 +++--- .../src/llms/tests/layerup_security.test.ts | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libs/langchain-community/src/llms/layerup_security.ts b/libs/langchain-community/src/llms/layerup_security.ts index e60676094892..5d84e7188add 100644 --- a/libs/langchain-community/src/llms/layerup_security.ts +++ b/libs/langchain-community/src/llms/layerup_security.ts @@ -1,7 +1,7 @@ import { LLM, BaseLLM, - type BaseLLMParams, + type BaseLLMCallOptions, } from "@langchain/core/language_models/llms"; import { GuardrailResponse, @@ -9,7 +9,7 @@ import { LLMMessage, } from "@layerup/layerup-security"; -export interface LayerupSecurityOptions extends BaseLLMParams { +export interface LayerupSecurityOptions extends BaseLLMCallOptions { llm: BaseLLM; layerupApiKey?: string; layerupApiBaseUrl?: string; @@ -101,7 +101,7 @@ export class LayerupSecurity extends LLM { return "layerup_security"; } - async _call(input: string, options?: BaseLLMParams): Promise { + async _call(input: string, options?: BaseLLMCallOptions): Promise { // Since LangChain LLMs only support string inputs, we will wrap each call to Layerup in a single-message // array of messages, then extract the string element when we need to access it. let messages: LLMMessage[] = [ diff --git a/libs/langchain-community/src/llms/tests/layerup_security.test.ts b/libs/langchain-community/src/llms/tests/layerup_security.test.ts index 670a56ca200b..883dca6fd0cb 100644 --- a/libs/langchain-community/src/llms/tests/layerup_security.test.ts +++ b/libs/langchain-community/src/llms/tests/layerup_security.test.ts @@ -1,5 +1,8 @@ import { test } from "@jest/globals"; -import { LLM, type BaseLLMParams } from "@langchain/core/language_models/llms"; +import { + LLM, + type BaseLLMCallOptions, +} from "@langchain/core/language_models/llms"; import { GuardrailResponse } from "@layerup/layerup-security/types.js"; import { LayerupSecurity, @@ -18,7 +21,7 @@ export class MockLLM extends LLM { return "mock_llm"; } - async _call(_input: string, _options?: BaseLLMParams): Promise { + async _call(_input: string, _options?: BaseLLMCallOptions): Promise { return "Hi Bob! How are you?"; } } From abda1e8d57aca3bdda5c4384a4d5348ab05404c9 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Thu, 1 Aug 2024 10:13:21 -0700 Subject: [PATCH 7/7] Make notebook validation only run in core_docs (#6312) --- .github/workflows/validate_new_notebooks.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/validate_new_notebooks.yml b/.github/workflows/validate_new_notebooks.yml index cce0fc05b67f..bb6bffebc062 100644 --- a/.github/workflows/validate_new_notebooks.yml +++ b/.github/workflows/validate_new_notebooks.yml @@ -36,23 +36,23 @@ jobs: - name: Get changed files id: changed-files uses: tj-actions/changed-files@v44 - - name: Check for new or modified notebooks + - name: Check for new or modified notebooks in docs/core_docs id: check_notebooks run: | - notebooks=$(echo '${{ steps.changed-files.outputs.all_changed_files }}' | tr ' ' '\n' | grep '\.ipynb$' || true) + notebooks=$(echo '${{ steps.changed-files.outputs.all_changed_files }}' | tr ' ' '\n' | grep '^docs/core_docs/.*\.ipynb$' || true) echo "Affected notebooks: $notebooks" echo "has_affected_notebooks=$([ -n "$notebooks" ] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT - name: Build examples if: steps.check_notebooks.outputs.has_affected_notebooks == 'true' run: yarn turbo:command build --filter=examples - - name: Validate affected notebooks + - name: Validate affected notebooks in docs/core_docs if: steps.check_notebooks.outputs.has_affected_notebooks == 'true' run: | - notebooks=$(echo '${{ steps.changed-files.outputs.all_changed_files }}' | tr ' ' '\n' | grep '\.ipynb$' || true) + notebooks=$(echo '${{ steps.changed-files.outputs.all_changed_files }}' | tr ' ' '\n' | grep '^docs/core_docs/.*\.ipynb$' || true) if [ -n "$notebooks" ]; then for notebook in $notebooks; do yarn notebook:validate "$notebook" done else - echo "No notebooks to validate." + echo "No notebooks in docs/core_docs to validate." fi \ No newline at end of file