Skip to content

Commit

Permalink
Merge branch 'main' into migrate-to-weaviate-v3-client
Browse files Browse the repository at this point in the history
  • Loading branch information
my8bit authored Jan 30, 2025
2 parents 2b72eee + 05eedae commit f189e5b
Show file tree
Hide file tree
Showing 13 changed files with 278 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion docs/core_docs/docs/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion langchain/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "langchain",
"version": "0.3.14",
"version": "0.3.15",
"description": "Typescript bindings for langchain",
"type": "module",
"engines": {
Expand Down
30 changes: 26 additions & 4 deletions langchain/src/hub/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,6 @@ export function generateModelImportMap(
) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const modelImportMap: Record<string, any> = {};
// 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();
Expand Down Expand Up @@ -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<string, any> = {};
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;
}
9 changes: 7 additions & 2 deletions langchain/src/hub/index.ts
Original file line number Diff line number Diff line change
@@ -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 };

Expand Down Expand Up @@ -36,7 +41,7 @@ export async function pull<T extends Runnable>(
const loadedPrompt = await load<T>(
JSON.stringify(promptObject.manifest),
undefined,
undefined,
generateOptionalImportMap(options?.modelClass),
generateModelImportMap(options?.modelClass)
);
return loadedPrompt;
Expand Down
9 changes: 7 additions & 2 deletions langchain/src/hub/node.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -55,7 +60,7 @@ export async function pull<T extends Runnable>(
const loadedPrompt = await load<T>(
JSON.stringify(promptObject.manifest),
undefined,
undefined,
generateOptionalImportMap(modelClass),
generateModelImportMap(modelClass)
);
return loadedPrompt;
Expand Down
7 changes: 4 additions & 3 deletions langchain/src/hub/tests/hub.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
2 changes: 1 addition & 1 deletion libs/langchain-community/package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
3 changes: 3 additions & 0 deletions libs/langchain-community/src/structured_query/supabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Operator,
Operators,
StructuredQuery,
isBoolean,
} from "@langchain/core/structured_query";
import type {
SupabaseFilterRPCCall,
Expand Down Expand Up @@ -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");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Loading

0 comments on commit f189e5b

Please sign in to comment.