From 3c53dcd561705ce3057d80271690d4cae4c236d4 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Wed, 29 Jan 2025 13:00:39 -0800 Subject: [PATCH 1/8] fix(langchain): Fix Groq import for hub (#7620) --- langchain/src/hub/base.ts | 30 +++++++++++++++++++++---- langchain/src/hub/index.ts | 9 ++++++-- langchain/src/hub/node.ts | 9 ++++++-- langchain/src/hub/tests/hub.int.test.ts | 7 +++--- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/langchain/src/hub/base.ts b/langchain/src/hub/base.ts index 6b4c2de020c5..6850cd37f2bd 100644 --- a/langchain/src/hub/base.ts +++ b/langchain/src/hub/base.ts @@ -96,10 +96,6 @@ export function generateModelImportMap( ) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const modelImportMap: Record = {}; - // TODO: Fix in 0.4.0. We can't get lc_id without instantiating the class, so we - // must put them inline here. In the future, make this less hacky - // This should probably use dynamic imports and have a web-only entrypoint - // in a future breaking release if (modelClass !== undefined) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const modelLcName = (modelClass as any)?.lc_name(); @@ -130,3 +126,29 @@ export function generateModelImportMap( } return modelImportMap; } + +export function generateOptionalImportMap( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + modelClass?: new (...args: any[]) => BaseLanguageModel +) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const optionalImportMap: Record = {}; + if (modelClass !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const modelLcName = (modelClass as any)?.lc_name(); + let optionalImportMapKey; + if (modelLcName === "ChatGoogleGenerativeAI") { + optionalImportMapKey = "langchain_google_genai/chat_models"; + } else if (modelLcName === "ChatBedrockConverse") { + optionalImportMapKey = "langchain_aws/chat_models"; + } else if (modelLcName === "ChatGroq") { + optionalImportMapKey = "langchain_groq/chat_models"; + } + if (optionalImportMapKey !== undefined) { + optionalImportMap[optionalImportMapKey] = { + [modelLcName]: modelClass, + }; + } + } + return optionalImportMap; +} diff --git a/langchain/src/hub/index.ts b/langchain/src/hub/index.ts index 71377ba0f11c..ba7ae918ee22 100644 --- a/langchain/src/hub/index.ts +++ b/langchain/src/hub/index.ts @@ -1,7 +1,12 @@ import { Runnable } from "@langchain/core/runnables"; import type { BaseLanguageModel } from "@langchain/core/language_models/base"; import { load } from "../load/index.js"; -import { basePush, basePull, generateModelImportMap } from "./base.js"; +import { + basePush, + basePull, + generateModelImportMap, + generateOptionalImportMap, +} from "./base.js"; export { basePush as push }; @@ -36,7 +41,7 @@ export async function pull( const loadedPrompt = await load( JSON.stringify(promptObject.manifest), undefined, - undefined, + generateOptionalImportMap(options?.modelClass), generateModelImportMap(options?.modelClass) ); return loadedPrompt; diff --git a/langchain/src/hub/node.ts b/langchain/src/hub/node.ts index ab01777f5d2a..10e0f8940bec 100644 --- a/langchain/src/hub/node.ts +++ b/langchain/src/hub/node.ts @@ -1,5 +1,10 @@ import { Runnable } from "@langchain/core/runnables"; -import { basePush, basePull, generateModelImportMap } from "./base.js"; +import { + basePush, + basePull, + generateModelImportMap, + generateOptionalImportMap, +} from "./base.js"; import { load } from "../load/index.js"; // TODO: Make this the default, add web entrypoint in next breaking release @@ -55,7 +60,7 @@ export async function pull( const loadedPrompt = await load( JSON.stringify(promptObject.manifest), undefined, - undefined, + generateOptionalImportMap(modelClass), generateModelImportMap(modelClass) ); return loadedPrompt; diff --git a/langchain/src/hub/tests/hub.int.test.ts b/langchain/src/hub/tests/hub.int.test.ts index 130e3d3e9bb9..f1c870cd6753 100644 --- a/langchain/src/hub/tests/hub.int.test.ts +++ b/langchain/src/hub/tests/hub.int.test.ts @@ -79,12 +79,13 @@ test("Test LangChain Hub while loading model", async () => { }); test("Test LangChain Hub while loading model with dynamic imports", async () => { - const pulledPrompt = await nodePull("jacob/lahzo-testing", { + const pulledPrompt = await nodePull("jacob/groq-test", { includeModel: true, }); const res = await pulledPrompt.invoke({ - agent: { name: "testing" }, - messages: [new AIMessage("foo")], + question: + "Who is the current president of the USA as of today? You must use the provided tool for the latest info.", }); expect(res).toBeInstanceOf(AIMessage); + expect(res.tool_calls?.length).toEqual(1); }); From b70a84ec43fdbdf698fa49580e112291ef99128a Mon Sep 17 00:00:00 2001 From: vbarda Date: Wed, 29 Jan 2025 18:56:07 -0500 Subject: [PATCH 2/8] docs: update README/intro --- README.md | 2 +- docs/core_docs/docs/introduction.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8f6f01684bd..b4ee9c5ed54b 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The LangChain libraries themselves are made up of several different packages. - **[`@langchain/core`](https://github.com/langchain-ai/langchainjs/blob/main/langchain-core)**: Base abstractions and LangChain Expression Language. - **[`@langchain/community`](https://github.com/langchain-ai/langchainjs/blob/main/libs/langchain-community)**: Third party integrations. - **[`langchain`](https://github.com/langchain-ai/langchainjs/blob/main/langchain)**: Chains, agents, and retrieval strategies that make up an application's cognitive architecture. -- **[LangGraph.js](https://langchain-ai.github.io/langgraphjs/)**: A library for building robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph. Integrates smoothly with LangChain, but can be used without it. +- **[LangGraph.js](https://langchain-ai.github.io/langgraphjs/)**: LangGraph powers production-grade agents, trusted by Linkedin, Uber, Klarna, GitLab, and many more. Build robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph. Integrates smoothly with LangChain, but can be used without it. Integrations may also be split into their own compatible packages. diff --git a/docs/core_docs/docs/introduction.mdx b/docs/core_docs/docs/introduction.mdx index d8a3df68ae83..68a1c8ef09ba 100644 --- a/docs/core_docs/docs/introduction.mdx +++ b/docs/core_docs/docs/introduction.mdx @@ -81,7 +81,7 @@ Trace and evaluate your language model applications and intelligent agents to he ### [🦜🕸️ LangGraph](https://langchain-ai.github.io/langgraphjs/) -Build stateful, multi-actor applications with LLMs, built on top of (and intended to be used with) LangChain primitives. +Build stateful, multi-actor applications with LLMs. Integrates smoothly with LangChain, but can be used without it. LangGraph powers production-grade agents, trusted by Linkedin, Uber, Klarna, GitLab, and many more. ## Additional resources From 0e37db8ef5d040630d7dba422ca1165516bfc81a Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Wed, 29 Jan 2025 15:57:07 -0800 Subject: [PATCH 3/8] Release 0.3.15 --- langchain/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langchain/package.json b/langchain/package.json index e2a52156e15a..f7a81958c592 100644 --- a/langchain/package.json +++ b/langchain/package.json @@ -1,6 +1,6 @@ { "name": "langchain", - "version": "0.3.14", + "version": "0.3.15", "description": "Typescript bindings for langchain", "type": "module", "engines": { From b4d924f008ad605a123bcd6a226215fcbb41fb95 Mon Sep 17 00:00:00 2001 From: Hugo Borsoni <44852104+hugoleborso@users.noreply.github.com> Date: Thu, 30 Jan 2025 01:05:56 +0100 Subject: [PATCH 4/8] feat(community): improve support for Tavily search tool args (#7561) --- .../src/tools/tavily_search.ts | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/libs/langchain-community/src/tools/tavily_search.ts b/libs/langchain-community/src/tools/tavily_search.ts index b83a042f7888..fde1e8986407 100644 --- a/libs/langchain-community/src/tools/tavily_search.ts +++ b/libs/langchain-community/src/tools/tavily_search.ts @@ -6,9 +6,86 @@ import { getEnvironmentVariable } from "@langchain/core/utils/env"; * Options for the TavilySearchResults tool. */ export type TavilySearchAPIRetrieverFields = ToolParams & { + /** + * The maximum number of search results to return. + * + * @default 5 + */ maxResults?: number; + + /** + * Additional keyword arguments to pass to the API. + */ kwargs?: Record; + + /** + * The API key used for authentication with the Tavily Search API. + * + */ apiKey?: string; + + /** + * Include a list of query-related images in the response. + * + * @default false + */ + includeImages?: boolean; + + /** + * When includeImages is set to True, this option adds descriptive text for each image. + * + * @default false + */ + includeImageDescriptions?: boolean; + + /** + * Include a short answer to the original query. + * + * @default false + */ + includeAnswer?: boolean; + + /** + * Include the cleaned and parsed HTML content of each search result. + * + * @default false + */ + includeRawContent?: boolean; + + /** + * A list of domains to specifically include in the search results. + * + * @default [] + */ + includeDomains?: string[]; + + /** + * A list of domains to specifically exclude from the search results. + * + * @default [] + */ + excludeDomains?: string[]; + + /** + * The depth of the search. It can be "basic" or "deep". + * + * @default "basic" + */ + searchDepth?: "basic" | "deep"; + + /** + * The category of the search. This will determine which of our agents will be used for the search. Currently, only "general" and "news" are supported. See https://docs.tavily.com/docs/rest-api/api-reference + * + * @default "general" + */ + topic?: string; + + /** + * The number of days back from the current date to include in the search results. + * + * @default 3 + */ + days?: number; }; /** @@ -93,11 +170,41 @@ export class TavilySearchResults extends Tool { protected kwargs: Record = {}; + protected includeImages?: boolean; + + protected includeImageDescriptions?: boolean; + + protected includeAnswer?: boolean; + + protected includeRawContent?: boolean; + + protected includeDomains?: string[]; + + protected excludeDomains?: string[]; + + protected searchDepth?: "basic" | "deep"; + + protected topic?: string; + + protected days?: number; + constructor(fields?: TavilySearchAPIRetrieverFields) { super(fields); this.maxResults = fields?.maxResults ?? this.maxResults; this.kwargs = fields?.kwargs ?? this.kwargs; this.apiKey = fields?.apiKey ?? getEnvironmentVariable("TAVILY_API_KEY"); + this.includeImages = fields?.includeImages ?? this.includeImages; + this.includeImageDescriptions = + fields?.includeImageDescriptions ?? this.includeImageDescriptions; + this.includeAnswer = fields?.includeAnswer ?? this.includeAnswer; + this.includeRawContent = + fields?.includeRawContent ?? this.includeRawContent; + this.includeDomains = fields?.includeDomains ?? this.includeDomains; + this.excludeDomains = fields?.excludeDomains ?? this.excludeDomains; + this.searchDepth = fields?.searchDepth ?? this.searchDepth; + this.topic = fields?.topic ?? this.topic; + this.days = fields?.days ?? this.days; + if (this.apiKey === undefined) { throw new Error( `No Tavily API key found. Either set an environment variable named "TAVILY_API_KEY" or pass an API key as "apiKey".` @@ -113,6 +220,15 @@ export class TavilySearchResults extends Tool { query: input, max_results: this.maxResults, api_key: this.apiKey, + include_images: this.includeImages, + include_image_descriptions: this.includeImageDescriptions, + include_answer: this.includeAnswer, + include_raw_content: this.includeRawContent, + include_domains: this.includeDomains, + exclude_domains: this.excludeDomains, + search_depth: this.searchDepth, + topic: this.topic, + days: this.days, }; const response = await fetch("https://api.tavily.com/search", { From ad4d0c91c6951f289eac567869a6373256d89291 Mon Sep 17 00:00:00 2001 From: Arman Ghazaryan Date: Thu, 30 Jan 2025 04:06:09 +0400 Subject: [PATCH 5/8] feat(community): Add boolean metadata type support in Supabase structured query translator (#7601) --- .../src/structured_query/supabase.ts | 3 + .../tests/supabase_self_query.int.test.ts | 102 ++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/libs/langchain-community/src/structured_query/supabase.ts b/libs/langchain-community/src/structured_query/supabase.ts index 602f46bfebfa..4d5fe64be3c0 100644 --- a/libs/langchain-community/src/structured_query/supabase.ts +++ b/libs/langchain-community/src/structured_query/supabase.ts @@ -12,6 +12,7 @@ import { Operator, Operators, StructuredQuery, + isBoolean, } from "@langchain/core/structured_query"; import type { SupabaseFilterRPCCall, @@ -134,6 +135,8 @@ export class SupabaseTranslator< column = `metadata->${attr}${includeType ? "::int" : ""}`; } else if (isFloat(value)) { column = `metadata->${attr}${includeType ? "::float" : ""}`; + } else if (isBoolean(value)) { + column = `metadata->${attr}${includeType ? "::boolean" : ""}`; } else { throw new Error("Data type not supported"); } diff --git a/libs/langchain-community/src/structured_query/tests/supabase_self_query.int.test.ts b/libs/langchain-community/src/structured_query/tests/supabase_self_query.int.test.ts index a6acd57934bb..5360065183b3 100644 --- a/libs/langchain-community/src/structured_query/tests/supabase_self_query.int.test.ts +++ b/libs/langchain-community/src/structured_query/tests/supabase_self_query.int.test.ts @@ -602,3 +602,105 @@ test("Supabase Store Self Query Retriever Test With Default Filter And Merge Ope // console.log(query4); expect(query4.length).toEqual(0); }); + +test("Supabase Store Self Query Retriever Test With Boolean Filters", async () => { + const docs = [ + new Document({ + pageContent: "A fun family movie about toys coming to life", + metadata: { + type: "movie", + year: 1995, + genre: "animated", + isKidsMovie: true, + hasSequels: true, + }, + }), + new Document({ + pageContent: "A dark psychological thriller about dreams", + metadata: { + type: "movie", + year: 2010, + director: "Christopher Nolan", + rating: 8.2, + isKidsMovie: false, + hasSequels: false, + }, + }), + new Document({ + pageContent: "A classic dinosaur adventure park goes wrong", + metadata: { + type: "movie", + year: 1993, + rating: 7.7, + genre: "science fiction", + isKidsMovie: false, + hasSequels: true, + }, + }), + ]; + + const attributeInfo: AttributeInfo[] = [ + { + name: "isKidsMovie", + description: "Whether the movie is made for children", + type: "boolean", + }, + { + name: "hasSequels", + description: "Whether the movie has sequel movies", + type: "boolean", + }, + { + name: "year", + description: "The year the movie was released", + type: "number", + }, + ]; + + if ( + !process.env.SUPABASE_VECTOR_STORE_URL || + !process.env.SUPABASE_VECTOR_STORE_PRIVATE_KEY + ) { + throw new Error( + "Supabase URL or private key not set. Please set it in the .env file" + ); + } + + const embeddings = new OpenAIEmbeddings(); + const llm = new OpenAI(); + const documentContents = "Brief summary of a movie"; + const client = createClient( + process.env.SUPABASE_VECTOR_STORE_URL, + process.env.SUPABASE_VECTOR_STORE_PRIVATE_KEY + ); + const vectorStore = new SupabaseVectorStore(embeddings, { client }); + // idempotency + const opts = { ids: docs.map((_, idx) => idx) }; + await vectorStore.addDocuments(docs, opts); + const selfQueryRetriever = SelfQueryRetriever.fromLLM({ + llm, + vectorStore, + documentContents, + attributeInfo, + structuredQueryTranslator: new SupabaseTranslator(), + }); + + const query1 = await selfQueryRetriever.getRelevantDocuments( + "Which movies are made for kids?" + ); + expect(query1.length).toEqual(1); + expect(query1[0].metadata.isKidsMovie).toBe(true); + + const query2 = await selfQueryRetriever.getRelevantDocuments( + "Which movies have sequels?" + ); + expect(query2.length).toEqual(2); + expect(query2.every((doc: Document) => doc.metadata.hasSequels)).toBe(true); + + const query3 = await selfQueryRetriever.getRelevantDocuments( + "Which movies are not made for kids and have sequels?" + ); + expect(query3.length).toEqual(1); + expect(query3[0].metadata.isKidsMovie).toBe(false); + expect(query3[0].metadata.hasSequels).toBe(true); +}); From 5f2b7b0676d8cdcddbe1b8be4bef15f84e91c429 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 30 Jan 2025 10:21:04 +0800 Subject: [PATCH 6/8] feat(google-genai): Add support for fileUri in media type in Google GenAI (#7621) Co-authored-by: Jacob Lee --- libs/langchain-google-genai/src/utils/common.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/langchain-google-genai/src/utils/common.ts b/libs/langchain-google-genai/src/utils/common.ts index c83528450c41..deee3fefbae6 100644 --- a/libs/langchain-google-genai/src/utils/common.ts +++ b/libs/langchain-google-genai/src/utils/common.ts @@ -81,6 +81,14 @@ function messageContentMedia(content: MessageContentComplex): Part { }, }; } + if ("mimeType" in content && "fileUri" in content) { + return { + fileData: { + mimeType: content.mimeType, + fileUri: content.fileUri, + }, + }; + } throw new Error("Invalid media content"); } From 0e48a753fb360347055fe2967e170251ea3e7f71 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Wed, 29 Jan 2025 18:23:39 -0800 Subject: [PATCH 7/8] release(google-genai): 0.1.8 (#7628) --- libs/langchain-google-genai/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langchain-google-genai/package.json b/libs/langchain-google-genai/package.json index 96f58b431db8..ace9f680ecc3 100644 --- a/libs/langchain-google-genai/package.json +++ b/libs/langchain-google-genai/package.json @@ -1,6 +1,6 @@ { "name": "@langchain/google-genai", - "version": "0.1.7", + "version": "0.1.8", "description": "Google Generative AI integration for LangChain.js", "type": "module", "engines": { From 05eedaef614914e5e19193ce24c36726b8ba4487 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Wed, 29 Jan 2025 18:28:27 -0800 Subject: [PATCH 8/8] release(community): 0.3.28 (#7629) --- libs/langchain-community/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langchain-community/package.json b/libs/langchain-community/package.json index 069626fcced9..6b59f23ee454 100644 --- a/libs/langchain-community/package.json +++ b/libs/langchain-community/package.json @@ -1,6 +1,6 @@ { "name": "@langchain/community", - "version": "0.3.27", + "version": "0.3.28", "description": "Third-party integrations for LangChain.js", "type": "module", "engines": {