langchain 0.2.3 → 0.2.5

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.
package/README.md CHANGED
@@ -57,7 +57,7 @@ This library aims to assist in the development of those types of applications. C
57
57
 
58
58
  **❓Question Answering over specific documents**
59
59
 
60
- - [Documentation](https://js.langchain.com/docs/use_cases/question_answering/)
60
+ - [Documentation](https://js.langchain.com/v0.2/docs/tutorials/rag)
61
61
  - End-to-end Example: [Doc-Chatbot](https://github.com/dissorial/doc-chatbot)
62
62
 
63
63
 
@@ -95,7 +95,7 @@ Please see [here](https://js.langchain.com/v0.2/) for full documentation, which
95
95
  - [Getting started](https://js.langchain.com/v0.2/docs/introduction): installation, setting up the environment, simple examples
96
96
  - [Tutorials](https://js.langchain.com/v0.2/docs/tutorials/): interactive guides and walkthroughs of common use cases/tasks.
97
97
  - [Use case](https://js.langchain.com/v0.2/docs/how_to/) walkthroughs and best practices for every component of the LangChain library.
98
- - [Reference](https://v02.api.js.langchain.com): full API docs
98
+ - [Reference](https://api.js.langchain.com): full API docs
99
99
 
100
100
  ## 💁 Contributing
101
101
 
@@ -161,7 +161,10 @@ class AgentExecutorIterator extends serializable_1.Serializable {
161
161
  const callbackManager = await manager_1.CallbackManager.configure(this.callbacks ?? this.config?.callbacks, this.agentExecutor.callbacks, this.tags ?? this.config?.tags, this.agentExecutor.tags, this.metadata ?? this.config?.metadata, this.agentExecutor.metadata, {
162
162
  verbose: this.agentExecutor.verbose,
163
163
  });
164
- this.runManager = await callbackManager?.handleChainStart(this.agentExecutor.toJSON(), this.inputs, undefined, undefined, this.tags ?? this.config?.tags, this.metadata ?? this.config?.metadata, this.runName ?? this.config?.runName);
164
+ this.runManager = await callbackManager?.handleChainStart(this.agentExecutor.toJSON(), this.inputs, this.config?.runId, undefined, this.tags ?? this.config?.tags, this.metadata ?? this.config?.metadata, this.runName ?? this.config?.runName);
165
+ if (this.config !== undefined) {
166
+ delete this.config.runId;
167
+ }
165
168
  }
166
169
  }
167
170
  /**
@@ -191,9 +194,7 @@ class AgentExecutorIterator extends serializable_1.Serializable {
191
194
  const toolReturn = await this.agentExecutor._getToolReturn(nextStep);
192
195
  if (toolReturn) {
193
196
  output = await this.agentExecutor._return(toolReturn, this.intermediateSteps, runManager);
194
- if (this.runManager) {
195
- await this.runManager.handleChainEnd(output);
196
- }
197
+ await this.runManager?.handleChainEnd(output);
197
198
  await this.setFinalOutputs(output);
198
199
  }
199
200
  }
@@ -204,6 +205,7 @@ class AgentExecutorIterator extends serializable_1.Serializable {
204
205
  const output = await this.agentExecutor.agent.returnStoppedResponse(this.agentExecutor.earlyStoppingMethod, this.intermediateSteps, this.inputs);
205
206
  const returnedOutput = await this.agentExecutor._return(output, this.intermediateSteps, this.runManager);
206
207
  await this.setFinalOutputs(returnedOutput);
208
+ await this.runManager?.handleChainEnd(returnedOutput);
207
209
  return returnedOutput;
208
210
  }
209
211
  async _callNext() {
@@ -158,7 +158,10 @@ export class AgentExecutorIterator extends Serializable {
158
158
  const callbackManager = await CallbackManager.configure(this.callbacks ?? this.config?.callbacks, this.agentExecutor.callbacks, this.tags ?? this.config?.tags, this.agentExecutor.tags, this.metadata ?? this.config?.metadata, this.agentExecutor.metadata, {
159
159
  verbose: this.agentExecutor.verbose,
160
160
  });
161
- this.runManager = await callbackManager?.handleChainStart(this.agentExecutor.toJSON(), this.inputs, undefined, undefined, this.tags ?? this.config?.tags, this.metadata ?? this.config?.metadata, this.runName ?? this.config?.runName);
161
+ this.runManager = await callbackManager?.handleChainStart(this.agentExecutor.toJSON(), this.inputs, this.config?.runId, undefined, this.tags ?? this.config?.tags, this.metadata ?? this.config?.metadata, this.runName ?? this.config?.runName);
162
+ if (this.config !== undefined) {
163
+ delete this.config.runId;
164
+ }
162
165
  }
163
166
  }
164
167
  /**
@@ -188,9 +191,7 @@ export class AgentExecutorIterator extends Serializable {
188
191
  const toolReturn = await this.agentExecutor._getToolReturn(nextStep);
189
192
  if (toolReturn) {
190
193
  output = await this.agentExecutor._return(toolReturn, this.intermediateSteps, runManager);
191
- if (this.runManager) {
192
- await this.runManager.handleChainEnd(output);
193
- }
194
+ await this.runManager?.handleChainEnd(output);
194
195
  await this.setFinalOutputs(output);
195
196
  }
196
197
  }
@@ -201,6 +202,7 @@ export class AgentExecutorIterator extends Serializable {
201
202
  const output = await this.agentExecutor.agent.returnStoppedResponse(this.agentExecutor.earlyStoppingMethod, this.intermediateSteps, this.inputs);
202
203
  const returnedOutput = await this.agentExecutor._return(output, this.intermediateSteps, this.runManager);
203
204
  await this.setFinalOutputs(returnedOutput);
205
+ await this.runManager?.handleChainEnd(returnedOutput);
204
206
  return returnedOutput;
205
207
  }
206
208
  async _callNext() {
@@ -1,8 +1,24 @@
1
+ import { z } from "zod";
1
2
  import { test, expect } from "@jest/globals";
2
3
  import { ChatOpenAI } from "@langchain/openai";
3
4
  import { ChatPromptTemplate } from "@langchain/core/prompts";
5
+ import { DynamicStructuredTool } from "@langchain/core/tools";
4
6
  import { TavilySearchResults } from "../../util/testing/tools/tavily_search.js";
5
7
  import { AgentExecutor, createToolCallingAgent } from "../index.js";
8
+ const syntaxErrorTool = new DynamicStructuredTool({
9
+ name: "query",
10
+ description: "use this tool to generate and execute a query from a question using the index.",
11
+ schema: z.object({
12
+ index_name: z.string().describe("The name of the index to query."),
13
+ question: z.string().describe("The question to answer."),
14
+ }),
15
+ func: async (_params) => {
16
+ return JSON.stringify({
17
+ result: "-ERR Syntax error at offset 19 near Bronx",
18
+ query: 'FT.AGGREGATE bites "@Borough:{The Bronx} @Gender:{M}" GROUPBY 0 REDUCE COUNT 0',
19
+ });
20
+ },
21
+ });
6
22
  const tools = [new TavilySearchResults({ maxResults: 1 })];
7
23
  test("createToolCallingAgent works", async () => {
8
24
  const prompt = ChatPromptTemplate.fromMessages([
@@ -69,3 +85,38 @@ test("createToolCallingAgent stream events works", async () => {
69
85
  }
70
86
  }
71
87
  });
88
+ test("createToolCallingAgent stream events works for multiple turns", async () => {
89
+ const prompt = ChatPromptTemplate.fromMessages([
90
+ ["system", "You are a helpful assistant"],
91
+ ["placeholder", "{chat_history}"],
92
+ ["human", "{input}"],
93
+ ["placeholder", "{agent_scratchpad}"],
94
+ ]);
95
+ const llm = new ChatOpenAI({
96
+ modelName: "gpt-4o",
97
+ temperature: 0,
98
+ });
99
+ const agent = await createToolCallingAgent({
100
+ llm,
101
+ tools: [syntaxErrorTool],
102
+ prompt,
103
+ });
104
+ const agentExecutor = new AgentExecutor({
105
+ agent,
106
+ tools: [syntaxErrorTool],
107
+ maxIterations: 3,
108
+ });
109
+ const input = "Generate a query that looks up how many animals have been bitten in the Bronx.";
110
+ const eventStream = agentExecutor.streamEvents({
111
+ input,
112
+ }, {
113
+ version: "v2",
114
+ });
115
+ for await (const event of eventStream) {
116
+ const eventType = event.event;
117
+ console.log("Event type: ", eventType);
118
+ if (eventType === "on_chat_model_stream") {
119
+ console.log("Content: ", event.data);
120
+ }
121
+ }
122
+ });
@@ -154,6 +154,7 @@ class S3Loader extends base_js_1.BaseDocumentLoader {
154
154
  const unstructuredLoader = new this._UnstructuredLoader(filePath, options);
155
155
  const docs = await unstructuredLoader.load();
156
156
  return docs;
157
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
157
158
  }
158
159
  catch (e) {
159
160
  throw new Error(`Failed to load file ${filePath} using unstructured loader: ${e.message}`);
@@ -128,6 +128,7 @@ export class S3Loader extends BaseDocumentLoader {
128
128
  const unstructuredLoader = new this._UnstructuredLoader(filePath, options);
129
129
  const docs = await unstructuredLoader.load();
130
130
  return docs;
131
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
131
132
  }
132
133
  catch (e) {
133
134
  throw new Error(`Failed to load file ${filePath} using unstructured loader: ${e.message}`);
@@ -24,8 +24,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  return result;
25
25
  };
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.util__math = exports.util__document = exports.storage__in_memory = exports.storage__encoder_backed = exports.stores__message__in_memory = exports.stores__file__in_memory = exports.stores__doc__in_memory = exports.stores__doc__base = exports.retrievers__matryoshka_retriever = exports.retrievers__score_threshold = exports.retrievers__hyde = exports.retrievers__document_compressors__embeddings_filter = exports.retrievers__document_compressors__chain_extract = exports.retrievers__time_weighted = exports.retrievers__parent_document = exports.retrievers__multi_vector = exports.retrievers__multi_query = exports.retrievers__document_compressors = exports.retrievers__contextual_compression = exports.output_parsers = exports.callbacks = exports.document_transformers__openai_functions = exports.document_loaders__base = exports.memory__chat_memory = exports.memory__index = exports.memory = exports.text_splitter = exports.vectorstores__memory = exports.embeddings__fake = exports.embeddings__cache_backed = exports.chains__retrieval = exports.chains__openai_functions = exports.chains__history_aware_retriever = exports.chains__combine_documents__reduce = exports.chains__combine_documents = exports.chains = exports.tools__retriever = exports.tools__render = exports.tools__chain = exports.tools = exports.agents__openai__output_parser = exports.agents__xml__output_parser = exports.agents__react__output_parser = exports.agents__format_scratchpad__log_to_message = exports.agents__format_scratchpad__xml = exports.agents__format_scratchpad__log = exports.agents__format_scratchpad__openai_tools = exports.agents__format_scratchpad = exports.agents__toolkits = exports.agents = void 0;
28
- exports.schema__output = exports.schema__output_parser = exports.schema__runnable = exports.prompts__base = exports.prompts__pipeline = exports.prompts__image = exports.prompts__chat = exports.schema = exports.schema__messages = exports.prompts__prompt = exports.embeddings__openai = exports.llms__openai = exports.chat_models__openai = exports.schema__prompt_template = exports.schema__query_constructor = exports.indexes = exports.runnables__remote = exports.smith = exports.evaluation = exports.experimental__prompts__custom_format = exports.experimental__masking = exports.experimental__chains__violation_of_expectations = exports.experimental__plan_and_execute = exports.experimental__generative_agents = exports.experimental__babyagi = exports.experimental__openai_files = exports.experimental__openai_assistant = exports.experimental__autogpt = exports.util__time = void 0;
27
+ exports.util__document = exports.storage__in_memory = exports.storage__encoder_backed = exports.stores__message__in_memory = exports.stores__file__in_memory = exports.stores__doc__in_memory = exports.stores__doc__base = exports.retrievers__matryoshka_retriever = exports.retrievers__score_threshold = exports.retrievers__hyde = exports.retrievers__document_compressors__embeddings_filter = exports.retrievers__document_compressors__chain_extract = exports.retrievers__time_weighted = exports.retrievers__parent_document = exports.retrievers__multi_vector = exports.retrievers__multi_query = exports.retrievers__ensemble = exports.retrievers__document_compressors = exports.retrievers__contextual_compression = exports.output_parsers = exports.callbacks = exports.document_transformers__openai_functions = exports.document_loaders__base = exports.memory__chat_memory = exports.memory__index = exports.memory = exports.text_splitter = exports.vectorstores__memory = exports.embeddings__fake = exports.embeddings__cache_backed = exports.chains__retrieval = exports.chains__openai_functions = exports.chains__history_aware_retriever = exports.chains__combine_documents__reduce = exports.chains__combine_documents = exports.chains = exports.tools__retriever = exports.tools__render = exports.tools__chain = exports.tools = exports.agents__openai__output_parser = exports.agents__xml__output_parser = exports.agents__react__output_parser = exports.agents__format_scratchpad__log_to_message = exports.agents__format_scratchpad__xml = exports.agents__format_scratchpad__log = exports.agents__format_scratchpad__openai_tools = exports.agents__format_scratchpad = exports.agents__toolkits = exports.agents = void 0;
28
+ exports.schema__output = exports.schema__output_parser = exports.schema__runnable = exports.prompts__base = exports.prompts__pipeline = exports.prompts__image = exports.prompts__chat = exports.schema = exports.schema__messages = exports.prompts__prompt = exports.embeddings__openai = exports.llms__openai = exports.chat_models__openai = exports.schema__prompt_template = exports.schema__query_constructor = exports.indexes = exports.runnables__remote = exports.smith = exports.evaluation = exports.experimental__prompts__custom_format = exports.experimental__masking = exports.experimental__chains__violation_of_expectations = exports.experimental__plan_and_execute = exports.experimental__generative_agents = exports.experimental__babyagi = exports.experimental__openai_files = exports.experimental__openai_assistant = exports.experimental__autogpt = exports.util__time = exports.util__math = void 0;
29
29
  exports.agents = __importStar(require("../agents/index.cjs"));
30
30
  exports.agents__toolkits = __importStar(require("../agents/toolkits/index.cjs"));
31
31
  exports.agents__format_scratchpad = __importStar(require("../agents/format_scratchpad/openai_functions.cjs"));
@@ -59,6 +59,7 @@ exports.callbacks = __importStar(require("../callbacks/index.cjs"));
59
59
  exports.output_parsers = __importStar(require("../output_parsers/index.cjs"));
60
60
  exports.retrievers__contextual_compression = __importStar(require("../retrievers/contextual_compression.cjs"));
61
61
  exports.retrievers__document_compressors = __importStar(require("../retrievers/document_compressors/index.cjs"));
62
+ exports.retrievers__ensemble = __importStar(require("../retrievers/ensemble.cjs"));
62
63
  exports.retrievers__multi_query = __importStar(require("../retrievers/multi_query.cjs"));
63
64
  exports.retrievers__multi_vector = __importStar(require("../retrievers/multi_vector.cjs"));
64
65
  exports.retrievers__parent_document = __importStar(require("../retrievers/parent_document.cjs"));
@@ -31,6 +31,7 @@ export * as callbacks from "../callbacks/index.js";
31
31
  export * as output_parsers from "../output_parsers/index.js";
32
32
  export * as retrievers__contextual_compression from "../retrievers/contextual_compression.js";
33
33
  export * as retrievers__document_compressors from "../retrievers/document_compressors/index.js";
34
+ export * as retrievers__ensemble from "../retrievers/ensemble.js";
34
35
  export * as retrievers__multi_query from "../retrievers/multi_query.js";
35
36
  export * as retrievers__multi_vector from "../retrievers/multi_vector.js";
36
37
  export * as retrievers__parent_document from "../retrievers/parent_document.js";
@@ -32,6 +32,7 @@ export * as callbacks from "../callbacks/index.js";
32
32
  export * as output_parsers from "../output_parsers/index.js";
33
33
  export * as retrievers__contextual_compression from "../retrievers/contextual_compression.js";
34
34
  export * as retrievers__document_compressors from "../retrievers/document_compressors/index.js";
35
+ export * as retrievers__ensemble from "../retrievers/ensemble.js";
35
36
  export * as retrievers__multi_query from "../retrievers/multi_query.js";
36
37
  export * as retrievers__multi_vector from "../retrievers/multi_vector.js";
37
38
  export * as retrievers__parent_document from "../retrievers/parent_document.js";
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EnsembleRetriever = void 0;
4
+ const retrievers_1 = require("@langchain/core/retrievers");
5
+ /**
6
+ * Ensemble retriever that aggregates and orders the results of
7
+ * multiple retrievers by using weighted Reciprocal Rank Fusion.
8
+ */
9
+ class EnsembleRetriever extends retrievers_1.BaseRetriever {
10
+ static lc_name() {
11
+ return "EnsembleRetriever";
12
+ }
13
+ constructor(args) {
14
+ super(args);
15
+ Object.defineProperty(this, "lc_namespace", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: ["langchain", "retrievers", "ensemble_retriever"]
20
+ });
21
+ Object.defineProperty(this, "retrievers", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: void 0
26
+ });
27
+ Object.defineProperty(this, "weights", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: void 0
32
+ });
33
+ Object.defineProperty(this, "c", {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: 60
38
+ });
39
+ this.retrievers = args.retrievers;
40
+ this.weights =
41
+ args.weights ||
42
+ new Array(args.retrievers.length).fill(1 / args.retrievers.length);
43
+ this.c = args.c || 60;
44
+ }
45
+ async _getRelevantDocuments(query, runManager) {
46
+ return this._rankFusion(query, runManager);
47
+ }
48
+ async _rankFusion(query, runManager) {
49
+ const retrieverDocs = await Promise.all(this.retrievers.map((retriever, i) => retriever.invoke(query, {
50
+ callbacks: runManager?.getChild(`retriever_${i + 1}`),
51
+ })));
52
+ const fusedDocs = await this._weightedReciprocalRank(retrieverDocs);
53
+ return fusedDocs;
54
+ }
55
+ async _weightedReciprocalRank(docList) {
56
+ if (docList.length !== this.weights.length) {
57
+ throw new Error("Number of retrieved document lists must be equal to the number of weights.");
58
+ }
59
+ const rrfScoreDict = docList.reduce((rffScore, retrieverDoc, idx) => {
60
+ let rank = 1;
61
+ const weight = this.weights[idx];
62
+ while (rank <= retrieverDoc.length) {
63
+ const { pageContent } = retrieverDoc[rank - 1];
64
+ if (!rffScore[pageContent]) {
65
+ // eslint-disable-next-line no-param-reassign
66
+ rffScore[pageContent] = 0;
67
+ }
68
+ // eslint-disable-next-line no-param-reassign
69
+ rffScore[pageContent] += weight / (rank + this.c);
70
+ rank += 1;
71
+ }
72
+ return rffScore;
73
+ }, {});
74
+ const uniqueDocs = this._uniqueUnion(docList.flat());
75
+ const sortedDocs = Array.from(uniqueDocs).sort((a, b) => rrfScoreDict[b.pageContent] - rrfScoreDict[a.pageContent]);
76
+ return sortedDocs;
77
+ }
78
+ _uniqueUnion(documents) {
79
+ const documentSet = new Set();
80
+ const result = [];
81
+ for (const doc of documents) {
82
+ const key = doc.pageContent;
83
+ if (!documentSet.has(key)) {
84
+ documentSet.add(key);
85
+ result.push(doc);
86
+ }
87
+ }
88
+ return result;
89
+ }
90
+ }
91
+ exports.EnsembleRetriever = EnsembleRetriever;
@@ -0,0 +1,34 @@
1
+ import { BaseRetriever, BaseRetrieverInput } from "@langchain/core/retrievers";
2
+ import { Document, DocumentInterface } from "@langchain/core/documents";
3
+ import { CallbackManagerForRetrieverRun } from "@langchain/core/callbacks/manager";
4
+ export interface EnsembleRetrieverInput extends BaseRetrieverInput {
5
+ /** A list of retrievers to ensemble. */
6
+ retrievers: BaseRetriever[];
7
+ /**
8
+ * A list of weights corresponding to the retrievers. Defaults to equal
9
+ * weighting for all retrievers.
10
+ */
11
+ weights?: number[];
12
+ /**
13
+ * A constant added to the rank, controlling the balance between the importance
14
+ * of high-ranked items and the consideration given to lower-ranked items.
15
+ * Default is 60.
16
+ */
17
+ c?: number;
18
+ }
19
+ /**
20
+ * Ensemble retriever that aggregates and orders the results of
21
+ * multiple retrievers by using weighted Reciprocal Rank Fusion.
22
+ */
23
+ export declare class EnsembleRetriever extends BaseRetriever {
24
+ static lc_name(): string;
25
+ lc_namespace: string[];
26
+ retrievers: BaseRetriever[];
27
+ weights: number[];
28
+ c: number;
29
+ constructor(args: EnsembleRetrieverInput);
30
+ _getRelevantDocuments(query: string, runManager?: CallbackManagerForRetrieverRun): Promise<Document<Record<string, any>>[]>;
31
+ _rankFusion(query: string, runManager?: CallbackManagerForRetrieverRun): Promise<Document<Record<string, any>>[]>;
32
+ _weightedReciprocalRank(docList: DocumentInterface[][]): Promise<Document<Record<string, any>>[]>;
33
+ private _uniqueUnion;
34
+ }
@@ -0,0 +1,87 @@
1
+ import { BaseRetriever } from "@langchain/core/retrievers";
2
+ /**
3
+ * Ensemble retriever that aggregates and orders the results of
4
+ * multiple retrievers by using weighted Reciprocal Rank Fusion.
5
+ */
6
+ export class EnsembleRetriever extends BaseRetriever {
7
+ static lc_name() {
8
+ return "EnsembleRetriever";
9
+ }
10
+ constructor(args) {
11
+ super(args);
12
+ Object.defineProperty(this, "lc_namespace", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: ["langchain", "retrievers", "ensemble_retriever"]
17
+ });
18
+ Object.defineProperty(this, "retrievers", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: void 0
23
+ });
24
+ Object.defineProperty(this, "weights", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: void 0
29
+ });
30
+ Object.defineProperty(this, "c", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: 60
35
+ });
36
+ this.retrievers = args.retrievers;
37
+ this.weights =
38
+ args.weights ||
39
+ new Array(args.retrievers.length).fill(1 / args.retrievers.length);
40
+ this.c = args.c || 60;
41
+ }
42
+ async _getRelevantDocuments(query, runManager) {
43
+ return this._rankFusion(query, runManager);
44
+ }
45
+ async _rankFusion(query, runManager) {
46
+ const retrieverDocs = await Promise.all(this.retrievers.map((retriever, i) => retriever.invoke(query, {
47
+ callbacks: runManager?.getChild(`retriever_${i + 1}`),
48
+ })));
49
+ const fusedDocs = await this._weightedReciprocalRank(retrieverDocs);
50
+ return fusedDocs;
51
+ }
52
+ async _weightedReciprocalRank(docList) {
53
+ if (docList.length !== this.weights.length) {
54
+ throw new Error("Number of retrieved document lists must be equal to the number of weights.");
55
+ }
56
+ const rrfScoreDict = docList.reduce((rffScore, retrieverDoc, idx) => {
57
+ let rank = 1;
58
+ const weight = this.weights[idx];
59
+ while (rank <= retrieverDoc.length) {
60
+ const { pageContent } = retrieverDoc[rank - 1];
61
+ if (!rffScore[pageContent]) {
62
+ // eslint-disable-next-line no-param-reassign
63
+ rffScore[pageContent] = 0;
64
+ }
65
+ // eslint-disable-next-line no-param-reassign
66
+ rffScore[pageContent] += weight / (rank + this.c);
67
+ rank += 1;
68
+ }
69
+ return rffScore;
70
+ }, {});
71
+ const uniqueDocs = this._uniqueUnion(docList.flat());
72
+ const sortedDocs = Array.from(uniqueDocs).sort((a, b) => rrfScoreDict[b.pageContent] - rrfScoreDict[a.pageContent]);
73
+ return sortedDocs;
74
+ }
75
+ _uniqueUnion(documents) {
76
+ const documentSet = new Set();
77
+ const result = [];
78
+ for (const doc of documents) {
79
+ const key = doc.pageContent;
80
+ if (!documentSet.has(key)) {
81
+ documentSet.add(key);
82
+ result.push(doc);
83
+ }
84
+ }
85
+ return result;
86
+ }
87
+ }
@@ -0,0 +1,74 @@
1
+ import { expect, test } from "@jest/globals";
2
+ import { CohereEmbeddings } from "@langchain/cohere";
3
+ import { MemoryVectorStore } from "../../vectorstores/memory.js";
4
+ import { EnsembleRetriever } from "../ensemble.js";
5
+ test("Should work with a question input", async () => {
6
+ const vectorstore = await MemoryVectorStore.fromTexts([
7
+ "Buildings are made out of brick",
8
+ "Buildings are made out of wood",
9
+ "Buildings are made out of stone",
10
+ "Cars are made out of metal",
11
+ "Cars are made out of plastic",
12
+ "mitochondria is the powerhouse of the cell",
13
+ "mitochondria is made of lipids",
14
+ ], [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }], new CohereEmbeddings());
15
+ const retriever = new EnsembleRetriever({
16
+ retrievers: [vectorstore.asRetriever()],
17
+ });
18
+ const query = "What are mitochondria made of?";
19
+ const retrievedDocs = await retriever.invoke(query);
20
+ expect(retrievedDocs[0].pageContent).toContain("mitochondria");
21
+ });
22
+ test("Should work with multiple retriever", async () => {
23
+ const vectorstore = await MemoryVectorStore.fromTexts([
24
+ "Buildings are made out of brick",
25
+ "Buildings are made out of wood",
26
+ "Buildings are made out of stone",
27
+ "Cars are made out of metal",
28
+ "Cars are made out of plastic",
29
+ "mitochondria is the powerhouse of the cell",
30
+ "mitochondria is made of lipids",
31
+ ], [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }], new CohereEmbeddings());
32
+ const vectorstore2 = await MemoryVectorStore.fromTexts([
33
+ "Buildings are made out of brick",
34
+ "Buildings are made out of wood",
35
+ "Buildings are made out of stone",
36
+ "Cars are made out of metal",
37
+ "Cars are made out of plastic",
38
+ "mitochondria is the powerhouse of the cell",
39
+ "mitochondria is made of lipids",
40
+ ], [{ id: 6 }, { id: 7 }, { id: 8 }, { id: 9 }, { id: 10 }], new CohereEmbeddings());
41
+ const retriever = new EnsembleRetriever({
42
+ retrievers: [vectorstore.asRetriever(), vectorstore2.asRetriever()],
43
+ });
44
+ const query = "cars";
45
+ const retrievedDocs = await retriever.invoke(query);
46
+ expect(retrievedDocs.filter((item) => item.pageContent.includes("Cars")).length).toBe(2);
47
+ });
48
+ test("Should work with weights", async () => {
49
+ const vectorstore = await MemoryVectorStore.fromTexts([
50
+ "Buildings are made out of brick",
51
+ "Buildings are made out of wood",
52
+ "Buildings are made out of stone",
53
+ "Cars are made out of metal",
54
+ "Cars are made out of plastic",
55
+ "mitochondria is the powerhouse of the cell",
56
+ "mitochondria is made of lipids",
57
+ ], [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }], new CohereEmbeddings());
58
+ const vectorstore2 = await MemoryVectorStore.fromTexts([
59
+ "Buildings are made out of brick",
60
+ "Buildings are made out of wood",
61
+ "Buildings are made out of stone",
62
+ "Cars are made out of metal",
63
+ "Cars are made out of plastic",
64
+ "mitochondria is the powerhouse of the cell",
65
+ "mitochondria is made of lipids",
66
+ ], [{ id: 6 }, { id: 7 }, { id: 8 }, { id: 9 }, { id: 10 }], new CohereEmbeddings());
67
+ const retriever = new EnsembleRetriever({
68
+ retrievers: [vectorstore.asRetriever(), vectorstore2.asRetriever()],
69
+ weights: [0.5, 0.9],
70
+ });
71
+ const query = "cars";
72
+ const retrievedDocs = await retriever.invoke(query);
73
+ expect(retrievedDocs.filter((item) => item.pageContent.includes("Cars")).length).toBe(2);
74
+ });
@@ -140,7 +140,7 @@ class CallbackManagerRunTree extends langsmith_1.RunTree {
140
140
  });
141
141
  this.callbackManager = callbackManager;
142
142
  }
143
- async createChild(config) {
143
+ createChild(config) {
144
144
  const child = new CallbackManagerRunTree({
145
145
  ...config,
146
146
  parent_run: this,
@@ -1,6 +1,6 @@
1
1
  import { Runnable } from "@langchain/core/runnables";
2
2
  import { Client, Feedback } from "langsmith";
3
- import type { TraceableFunction } from "langsmith/traceable";
3
+ import type { TraceableFunction } from "langsmith/singletons/traceable";
4
4
  import { type RunEvalConfig } from "./config.js";
5
5
  export type ChainOrFactory = Runnable | (() => Runnable) | AnyTraceableFunction | ((obj: any) => any) | ((obj: any) => Promise<any>) | (() => (obj: unknown) => unknown) | (() => (obj: unknown) => Promise<unknown>);
6
6
  type AnyTraceableFunction = TraceableFunction<(...any: any[]) => any>;
@@ -137,7 +137,7 @@ class CallbackManagerRunTree extends RunTree {
137
137
  });
138
138
  this.callbackManager = callbackManager;
139
139
  }
140
- async createChild(config) {
140
+ createChild(config) {
141
141
  const child = new CallbackManagerRunTree({
142
142
  ...config,
143
143
  parent_run: this,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langchain",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Typescript bindings for langchain",
5
5
  "type": "module",
6
6
  "engines": {
@@ -370,6 +370,10 @@
370
370
  "retrievers/document_compressors.js",
371
371
  "retrievers/document_compressors.d.ts",
372
372
  "retrievers/document_compressors.d.cts",
373
+ "retrievers/ensemble.cjs",
374
+ "retrievers/ensemble.js",
375
+ "retrievers/ensemble.d.ts",
376
+ "retrievers/ensemble.d.cts",
373
377
  "retrievers/multi_query.cjs",
374
378
  "retrievers/multi_query.js",
375
379
  "retrievers/multi_query.d.ts",
@@ -881,14 +885,14 @@
881
885
  },
882
886
  "dependencies": {
883
887
  "@langchain/core": "~0.2.0",
884
- "@langchain/openai": "~0.0.28",
888
+ "@langchain/openai": "~0.1.0",
885
889
  "@langchain/textsplitters": "~0.0.0",
886
890
  "binary-extensions": "^2.2.0",
887
891
  "js-tiktoken": "^1.0.12",
888
892
  "js-yaml": "^4.1.0",
889
893
  "jsonpointer": "^5.0.1",
890
894
  "langchainhub": "~0.0.8",
891
- "langsmith": "~0.1.7",
895
+ "langsmith": "~0.1.30",
892
896
  "ml-distance": "^4.0.0",
893
897
  "openapi-types": "^12.1.3",
894
898
  "p-retry": "4",
@@ -1725,6 +1729,15 @@
1725
1729
  "import": "./retrievers/document_compressors.js",
1726
1730
  "require": "./retrievers/document_compressors.cjs"
1727
1731
  },
1732
+ "./retrievers/ensemble": {
1733
+ "types": {
1734
+ "import": "./retrievers/ensemble.d.ts",
1735
+ "require": "./retrievers/ensemble.d.cts",
1736
+ "default": "./retrievers/ensemble.d.ts"
1737
+ },
1738
+ "import": "./retrievers/ensemble.js",
1739
+ "require": "./retrievers/ensemble.cjs"
1740
+ },
1728
1741
  "./retrievers/multi_query": {
1729
1742
  "types": {
1730
1743
  "import": "./retrievers/multi_query.d.ts",
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/retrievers/ensemble.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/retrievers/ensemble.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/retrievers/ensemble.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/retrievers/ensemble.js'