feat: VectoryMemoryBlock (#2110)

Co-authored-by: Marcus Schiesser <mail@marcusschiesser.de>
This commit is contained in:
Thuc Pham
2025-07-22 11:18:09 +07:00
committed by GitHub
parent 4d50ca4d84
commit 38da40bc98
14 changed files with 526 additions and 20 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"@llamaindex/doc": patch
"@llamaindex/core": patch
---
feat: VectoryMemoryBlock
@@ -106,34 +106,40 @@ const memory = createMemory({
Long-term memory is represented as `Memory Block` objects. These objects contain information that are from previous user sessions or from the beginning of the current conversation. When memory is retrieved (by calling `getLLM`), the short-term and long-term memories are merged together within the given `tokenLimit`.
Currently, there are two predefined memory blocks:
Currently, there are three predefined memory blocks:
- `staticBlock`: A memory block that stores a static piece of information.
- `factExtractionBlock`: A memory block that extracts facts from the chat history.
- `vectorBlock`: A memory block that stores and retrieves chat messages from a vector database using semantic similarity search. Messages are stored individually and retrieved based on their relevance to recent conversation context. Here we've passed in the `vectorStore` to use to store and retrieve the chat messages.
This sounds a bit complicated, but it's actually quite simple. Let's look at an example:
```ts
import { createMemory, factExtractionBlock, staticBlock } from "llamaindex";
import { createMemory, factExtractionBlock, staticBlock, vectorBlock } from "llamaindex";
import { QdrantVectorStore } from "@llamaindex/qdrant";
import { OpenAIEmbedding } from "@llamaindex/openai";
const memoryBlocks= [
staticBlock({
id: "core_info",
content: "My name is Logan, and I live in Saskatoon. I work at LlamaIndex.",
}),
factExtractionBlock({
id: "user-extracted_info",
priority: 1,
llm: llm,
maxFacts: 50,
}),
vectorBlock({
vectorStore: new QdrantVectorStore({ url: "http://localhost:6333" }),
priority: 2,
}),
];
```
Here, we've setup two memory blocks:
Here, we've setup three memory blocks:
- `core_info`: A static memory block that stores some core information about the user. This information will always be inserted into the memory. The type used is `MessageContent` to support multi-modal content.
- `extracted_info`: An extracted memory block that will extract information from the chat history. Here we've passed in the `llm` to use to extract facts from the chat history, and set the `maxFacts` to 50. If the number of extracted facts exceeds this limit, the `maxFacts` will be automatically summarized and reduced to leave room for new information.
- `staticBlock`: A static memory block that stores some core information about the user. This information will always be inserted into the memory. The type used is `MessageContent` to support multi-modal content.
- `factExtractionBlock`: An extracted memory block that will extract information from the chat history. Here we've passed in the `llm` to use to extract facts from the chat history, and set the `maxFacts` to 50. If the number of extracted facts exceeds this limit, the `maxFacts` will be automatically summarized and reduced to leave room for new information.
- `vectorBlock`: A vector memory block that will store in a vector database and retrieve them from there. Messages are stored individually and retrieved based on their relevance to recent conversation context. Here we've passed in the `vectorStore` to use to store and retrieve the chat messages.
You'll also notice that we've set the `priority` for the `factExtractionBlock` block. This is used to determine the handling when the memory blocks content (i.e. long-term memory) + short-term memory exceeds the token limit on the `Memory` object.
@@ -158,6 +164,46 @@ When memory is retrieved (using `getLLM`), the short-term and long-term memories
The amount of short-term memory included is specified by the `shortTermTokenLimitRatio`. If it's set to `0.7`, 70% of the `tokenLimit` is used for short-term memory (not including the static memory block).
#### VectorBlock Configuration Options
The `vectorBlock` offers several configuration options to customize its behavior:
```ts
vectorBlock({
vectorStore: new QdrantVectorStore({ url: "http://localhost:6333" }),
priority: 2,
retrievalContextWindow: 5, // Number of recent messages to use for context when retrieving
formatTemplate: new PromptTemplate({ template: "Context: {{ context }}" }), // Custom formatting template
nodePostprocessors: [/* custom postprocessors */], // Apply processing to retrieved nodes
queryOptions: {
similarityTopK: 3, // Number of top similar results to return (default: 2)
mode: VectorStoreQueryMode.DEFAULT, // Query mode for the vector store
sessionFilterKey: "session_id", // Metadata key for session filtering (default: "session_id")
// Custom filters can be added here - session filter is automatically included
filters: {
filters: [
{ key: "custom_field", value: "custom_value", operator: "==" }
],
condition: "and"
}
}
})
```
**Key Configuration Options:**
- **`retrievalContextWindow`**: Number of recent messages to consider when creating the retrieval query (default: 5). A larger window provides more context but may be less precise.
- **`formatTemplate`**: Template for formatting retrieved information before adding to memory. Defaults to a simple context template.
- **`nodePostprocessors`**: Array of postprocessors to apply to retrieved nodes, useful for filtering or transforming results.
- **`queryOptions.similarityTopK`**: Number of most similar messages to retrieve from the vector store (default: 2).
- **`queryOptions.sessionFilterKey`**: Metadata key used to isolate memory between different sessions (default: "session_id").
- **`queryOptions.filters`**: Additional metadata filters for retrieval. The session filter is automatically added to ensure memory isolation.
**Session Isolation:**
The vectorBlock automatically adds a session filter using the block's ID to ensure that memories from different sessions don't interfere with each other. This filter uses the `sessionFilterKey` (default: "session_id") and can be customized if needed.
## Persistence with Snapshots
Save and restore memory state:
+1 -1
View File
@@ -23,7 +23,7 @@ await test("pinecone", async (t) => {
});
const vectorStore = new PineconeVectorStore({
embeddingModel: openaiEmbedding,
embedModel: openaiEmbedding,
});
t.after(async () => {
+150
View File
@@ -0,0 +1,150 @@
/**
* Example: Vector Memory Block
*
* This example demonstrates how to use the VectorMemoryBlock to store and retrieve
* conversation history using vector similarity search. The vector memory block
* stores messages in a vector store and can retrieve relevant context based on
* semantic similarity to recent messages.
*/
import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
import { QdrantVectorStore } from "@llamaindex/qdrant";
import { createMemory, vectorBlock } from "llamaindex";
// Set up the LLM and embedding model
const llm = new OpenAI({ model: "gpt-4.1-mini" });
const embedModel = new OpenAIEmbedding({ model: "text-embedding-3-small" });
// Simulate a conversation with some context
// This conversation has 8 messages, which is more than the token limit of 100 tokens (set below)
// The last 4 messages are kept in to short term memory block (as their tokens are in the limit)
// Whereas the first 5 messages are added to long term memory block (in here we will use the vector memory block with Qdrant)
const CONVERSATION_TURNS = [
//// This is the first 5 messages that are added to long term memory block (vector memory block)
{
role: "user",
content: "Hi, I'm Sarah and I work as a data scientist at Google.",
},
{
role: "assistant",
content:
"Hello Sarah! It's great to meet you. Data science at Google must be exciting!",
},
{
role: "user",
content:
"Yes, I specialize in machine learning and natural language processing.",
},
{
role: "assistant",
content: "That's impressive! ML and NLP are fascinating fields.",
},
{
role: "user",
content:
"I have a PhD in Computer Science from Stanford, and I love hiking on weekends.",
},
//// This is the last 4 messages that are added to short term memory block
{
role: "assistant",
content:
"Wow, Stanford PhD! And hiking is a great way to unwind from tech work.",
},
{
role: "user",
content: "I also have two cats named Whiskers and Mittens.",
},
{
role: "assistant",
content:
"Cats make wonderful companions! Whiskers and Mittens are cute names.",
},
{
role: "user",
content: "Summary information about Sarah and her cats",
},
];
async function main() {
console.log("=== Vector Memory Block Example ===\n");
/**
* Create a vector store. You can quickly get a local instance of Qdrant running with Docker:
* ```bash
* docker pull qdrant/qdrant
* docker run -p 6333:6333 qdrant/qdrant
* ```
*
* Go to http://localhost:6333/dashboard#/collections to see your data
*/
const vectorStore = new QdrantVectorStore({
url: "http://localhost:6333",
embedModel,
});
// Create a vector memory block using the factory function
const vectorMemoryBlock = vectorBlock({
vectorStore,
priority: 5,
});
// Create a memory store with the vector memory block
const memory = createMemory([], {
llm,
memoryBlocks: [vectorMemoryBlock],
tokenLimit: 100,
shortTermTokenLimitRatio: 0.7,
});
// Store the conversation history in the vector memory
console.log(`Adding ${CONVERSATION_TURNS.length} messages to the memory...`);
for (const message of CONVERSATION_TURNS) {
await memory.add(message);
}
// Retrieve relevant context for the current user request
console.log("Retrieving relevant context...");
const chatHistory = await memory.getLLM();
// You will see there's 1 generated context message from vector memory block, and 4 messages from short term memory block
console.log("Chat memory:", chatHistory);
// Now simulate the assistant responding with context
console.log("\nAssistant response with context:");
const response = await llm.chat({
messages: chatHistory,
});
console.log(response.message.content);
// Try adding more messages to the memory
const newMessages = [
{
role: "user",
content: "Write a long paragraph about weather in Tokyo",
},
{
role: "assistant",
content:
"The weather in Tokyo is sunny and warm. The temperature is around 20 degrees Celsius. The weather is very nice and the people are friendly.",
},
{
role: "user",
content: "What is the weather in Tokyo?",
},
];
// Add the new messages to the memory
for (const message of newMessages) {
await memory.add(message);
}
// Try retrieving the new messages
const newChatHistory = await memory.getLLM();
// You can see now that new chat history will contain the nodes (separated by `\n`) in the
// context message that is generated by the vector memory block
// The number of retrieved nodes is set by `similarityTopK` in `queryOptions` of `vectorBlock`
// (default `similarityTopK` is 2)
console.log("New chat history:", newChatHistory);
}
main().catch(console.error);
+1 -1
View File
@@ -15,7 +15,7 @@ async function main() {
const vectorStore = new QdrantVectorStore({
url: process.env.QDRANT_URL,
apiKey: process.env.QDRANT_API_KEY,
embeddingModel: embedding,
embedModel: embedding,
collectionName: "gemini_test",
});
const storageContext = await storageContextFromDefaults({ vectorStore });
+1 -1
View File
@@ -16,7 +16,7 @@ async function main() {
const vectorStore = new QdrantVectorStore({
url: process.env.QDRANT_URL,
apiKey: process.env.QDRANT_API_KEY,
embeddingModel: embedding,
embedModel: embedding,
collectionName: "jina_test",
});
const storageContext = await storageContextFromDefaults({ vectorStore });
+3 -1
View File
@@ -39,7 +39,9 @@ export abstract class BaseMemoryBlock<
*
* @returns The memory block content as an array of ChatMessage.
*/
abstract get(): Promise<MemoryMessage<TAdditionalMessageOptions>[]>;
abstract get(
messages?: MemoryMessage<TAdditionalMessageOptions>[],
): Promise<MemoryMessage<TAdditionalMessageOptions>[]>;
/**
* Store the messages in the memory block.
+1
View File
@@ -1,3 +1,4 @@
export { BaseMemoryBlock } from "./base";
export { FactExtractionMemoryBlock } from "./fact";
export { StaticMemoryBlock } from "./static";
export { VectorMemoryBlock } from "./vector";
+250
View File
@@ -0,0 +1,250 @@
import type { BaseEmbedding } from "../../embeddings";
import type { BaseNodePostprocessor } from "../../postprocessor";
import { BasePromptTemplate, defaultContextSystemPrompt } from "../../prompts";
import type { NodeWithScore } from "../../schema";
import { MetadataMode, TextNode } from "../../schema";
import { extractText } from "../../utils/llms";
import type {
BaseVectorStore,
MetadataFilter,
VectorStoreQuery,
} from "../../vector-store";
import { VectorStoreQueryMode } from "../../vector-store";
import type { MemoryMessage } from "../types";
import { BaseMemoryBlock, type MemoryBlockOptions } from "./base";
/**
* The options for the vector memory block.
*/
export type VectorMemoryBlockOptions = {
/**
* The vector store to use for retrieval.
*/
vectorStore: BaseVectorStore;
/**
* Maximum number of messages to include for context when retrieving.
* @default 5
*/
retrievalContextWindow?: number;
/**
* Template for formatting the retrieved information.
* @default new PromptTemplate({ template: "{{ text }}" })
*/
formatTemplate?: BasePromptTemplate;
/**
* List of node postprocessors to apply to the retrieved nodes containing messages.
*
* @default []
*/
nodePostprocessors?: BaseNodePostprocessor[];
/**
* Configuration options for vector store queries when retrieving memory.
*
* @default
* ```typescript
* {
* similarityTopK: 2, // Number of top similar results to return
* mode: VectorStoreQueryMode.DEFAULT, // Query mode for the vector store
* sessionFilterKey: "session_id", // Metadata key for session filtering
* filters: {
* filters: [
* { key: "session_id", value: "<current block id>", operator: "==" }
* ],
* condition: "and"
* }
* }
* ```
*
* Note: A session filter is automatically added to ensure memory isolation between blocks.
* If custom filters are provided, the session filter will be merged with them.
*/
queryOptions?: Partial<VectorMemoryBlockQueryOptions>;
} & MemoryBlockOptions;
export type VectorMemoryBlockQueryOptions = Omit<
VectorStoreQuery,
"queryEmbedding" | "queryStr"
> & {
sessionFilterKey: string;
};
/**
* A memory block that retrieves relevant information from a vector store.
*
* This block stores conversation history in a vector store and retrieves
* relevant information based on the most recent messages.
*/
export class VectorMemoryBlock<
TAdditionalMessageOptions extends object = object,
> extends BaseMemoryBlock<TAdditionalMessageOptions> {
private readonly vectorStore: BaseVectorStore;
private readonly retrievalContextWindow: number;
private readonly formatTemplate: BasePromptTemplate;
private readonly nodePostprocessors: BaseNodePostprocessor[];
private readonly queryOptions: VectorMemoryBlockQueryOptions;
constructor(options: VectorMemoryBlockOptions) {
super(options);
// Validate vector store
if (!options.vectorStore.storesText) {
throw new Error(
"vectorStore must store text to be used as a retrieval memory block",
);
}
this.vectorStore = options.vectorStore;
this.retrievalContextWindow = options.retrievalContextWindow ?? 5;
this.queryOptions = this.buildDefaultQueryOptions(options.queryOptions);
this.formatTemplate = options.formatTemplate ?? defaultContextSystemPrompt;
this.nodePostprocessors = options.nodePostprocessors ?? [];
}
get embedModel(): BaseEmbedding {
return this.vectorStore.embedModel;
}
async get(
messages: MemoryMessage<TAdditionalMessageOptions>[] = [],
): Promise<MemoryMessage<TAdditionalMessageOptions>[]> {
if (messages?.length === 0) return [];
// Use the last message or a context window of messages for the query
let context: MemoryMessage<TAdditionalMessageOptions>[];
if (
this.retrievalContextWindow > 1 &&
messages.length >= this.retrievalContextWindow
) {
context = messages.slice(-this.retrievalContextWindow);
} else {
context = messages;
}
const queryText = context
.map((message) => extractText(message.content))
.join("\n\n");
if (!queryText) return [];
// Create and execute the query
const queryEmbedding = await this.embedModel.getTextEmbedding(queryText);
const query: VectorStoreQuery = {
queryStr: queryText,
queryEmbedding,
...this.queryOptions,
};
const results = await this.vectorStore.query(query);
if (!results.nodes?.length) return [];
// Create nodes with scores
const nodesWithScores: NodeWithScore[] = results.nodes.map(
(node, index) => ({
node,
score: results.similarities?.[index] ?? undefined,
}),
);
// Apply postprocessors
let processedNodes = nodesWithScores;
for (const postprocessor of this.nodePostprocessors) {
processedNodes = await postprocessor.postprocessNodes(
processedNodes,
queryText,
);
}
// Format the results
const retrievedText = processedNodes
.map(({ node }) => node.getContent(MetadataMode.NONE))
.join("\n\n");
const formattedText = this.formatTemplate.format({
context: retrievedText,
});
// Return as memory message
return [
{
id: this.id,
role: "memory",
content: formattedText,
} as MemoryMessage<TAdditionalMessageOptions>,
];
}
async put(
messages: MemoryMessage<TAdditionalMessageOptions>[],
): Promise<void> {
if (messages.length === 0) return;
// Format messages with role, text content, and additional info
const texts: string[] = [];
for (const message of messages) {
const text = extractText(message.content);
if (!text) continue;
let messageText = text;
// Add additional info if present
const additionalInfo = (message.options ?? {}) as Record<string, unknown>;
if (Object.keys(additionalInfo).length > 0) {
messageText += `\nAdditional Info: (${JSON.stringify(additionalInfo)})`;
}
texts.push(`<message role='${message.role}'>${messageText}</message>`);
}
if (texts.length === 0) return;
// Create text node with session metadata
const textNode = new TextNode({
text: texts.join("\n"),
metadata: { [this.queryOptions.sessionFilterKey]: this.id },
});
// Get embedding for the text
textNode.embedding = await this.embedModel.getTextEmbedding(textNode.text);
// Add to vector store
await this.vectorStore.add([textNode]);
}
private buildDefaultQueryOptions(
options: Partial<VectorMemoryBlockQueryOptions> | undefined,
): VectorMemoryBlockQueryOptions {
const {
similarityTopK = 2,
mode = VectorStoreQueryMode.DEFAULT,
sessionFilterKey = "session_id",
} = options ?? {};
let filters = options?.filters;
const sessionFilter: MetadataFilter = {
key: sessionFilterKey,
value: this.id,
operator: "==",
};
if (filters) {
// Only add session_id filter if it doesn't exist in the filters list
const sessionIdFilterExists = filters.filters.some(
(filter) => filter.key === sessionFilterKey,
);
if (!sessionIdFilterExists) {
filters.filters.push(sessionFilter);
}
} else {
// If no filters are provided, add the session_id filter
filters = {
filters: [sessionFilter],
condition: "and",
};
}
return { ...options, similarityTopK, mode, sessionFilterKey, filters };
}
}
+15
View File
@@ -8,6 +8,10 @@ import {
StaticMemoryBlock,
type StaticMemoryBlockOptions,
} from "./block/static";
import {
VectorMemoryBlock,
type VectorMemoryBlockOptions,
} from "./block/vector";
import { DEFAULT_TOKEN_LIMIT, Memory, type MemoryOptions } from "./memory";
import type { MemoryMessage } from "./types";
@@ -115,6 +119,17 @@ export function factExtractionBlock<TMessageOptions extends object = object>(
return new FactExtractionMemoryBlock<TMessageOptions>(options);
}
/**
* create a VectorMemoryBlock
* @param options - Configuration options for the vector memory block
* @returns A new VectorMemoryBlock instance
*/
export function vectorBlock<TMessageOptions extends object = object>(
options: VectorMemoryBlockOptions,
): VectorMemoryBlock<TMessageOptions> {
return new VectorMemoryBlock<TMessageOptions>(options);
}
/**
* Creates a new Memory instance from a snapshot
* @param snapshot The snapshot to load from
+36 -3
View File
@@ -31,6 +31,13 @@ export type MemoryOptions<TMessageOptions extends object = object> = {
* Used internally for memory restoration from snapshots.
*/
memoryCursor?: number;
/**
* The default LLM to use for memory retrieval.
* If not provided, the default `Settings.llm` will be used.
* This default LLM can be overridden by the LLM passed in the `getLLM` method.
*/
llm?: LLM | undefined;
};
export class Memory<
@@ -65,6 +72,10 @@ export class Memory<
* The cursor for the messages that have been processed into long-term memory.
*/
private memoryCursor: number = 0;
/**
* The default LLM to use for memory retrieval.
*/
private llm: LLM | undefined;
constructor(
messages: MemoryMessage<TMessageOptions>[] = [],
@@ -76,6 +87,7 @@ export class Memory<
options.shortTermTokenLimitRatio ?? DEFAULT_SHORT_TERM_TOKEN_LIMIT_RATIO;
this.memoryBlocks = options.memoryBlocks ?? [];
this.memoryCursor = options.memoryCursor ?? 0;
this.initLLM(options.llm);
this.adapters = {
...options.customAdapters,
@@ -84,6 +96,15 @@ export class Memory<
} as TAdapters & BuiltinAdapters<TMessageOptions>;
}
private initLLM(llm: LLM | undefined) {
// safe initialize LLM without throwing error if Settings.llm hasn't been set yet
try {
this.llm = llm ?? Settings.llm;
} catch (error) {
this.llm = undefined;
}
}
/**
* Add a message to the memory
* @param message - The message to add to the memory
@@ -160,12 +181,13 @@ export class Memory<
/**
* Get the messages from the memory, optionally including transient messages.
* only return messages that are within context window of the LLM
* @param llm - To fit the result messages to the context window of the LLM. If not provided, the default token limit will be used.
* @param llm - To fit the result messages to the context window of the LLM (fallback to default llm if not provided).
* If llm is not specified in both the constructor and the method, the default token limit will be used.
* @param transientMessages - Optional transient messages to include.
* @returns The messages from the memory, optionally including transient messages.
*/
async getLLM(
llm?: LLM,
llm: LLM | undefined = this.llm,
transientMessages?: ChatMessage<TMessageOptions>[],
): Promise<ChatMessage[]> {
// Priority of result messages:
@@ -176,11 +198,20 @@ export class Memory<
? Math.ceil(contextWindow * DEFAULT_TOKEN_LIMIT_RATIO)
: this.tokenLimit;
let blockInputMessages = this.messages;
if (transientMessages && transientMessages.length > 0) {
blockInputMessages = [
...this.messages,
...transientMessages.map((m) => this.adapters.llamaindex.toMemory(m)),
];
}
// Start with fixed block messages (priority=0)
// as it must always be included in the retrieval result
const messages = await this.getMemoryBlockMessages(
this.memoryBlocks.filter((block) => block.priority === 0),
tokenLimit,
blockInputMessages,
);
// remaining token limit for short-term and memory blocks content
const remainingTokenLimit =
@@ -207,6 +238,7 @@ export class Memory<
const longTermBlockMessages = await this.getMemoryBlockMessages(
longTermBlocks,
memoryBlocksTokenLimit,
blockInputMessages,
);
messages.push(...longTermBlockMessages);
@@ -252,6 +284,7 @@ export class Memory<
private async getMemoryBlockMessages(
blocks: BaseMemoryBlock<TMessageOptions>[],
tokenLimit?: number,
messages?: MemoryMessage<TMessageOptions>[],
): Promise<ChatMessage<TMessageOptions>[]> {
if (blocks.length === 0) {
return [];
@@ -265,7 +298,7 @@ export class Memory<
let addedTokenCount = 0;
for (const block of sortedBlocks) {
try {
const content = await block.get();
const content = await block.get(messages);
for (const message of content) {
const chatMessage = this.adapters.llamaindex.fromMemory(message);
const messageTokenCount = this.countMessagesToken([chatMessage]);
+4 -1
View File
@@ -101,7 +101,9 @@ export type VectorStoreByType = {
};
export type VectorStoreBaseParams = {
// @deprecated: use embedModel instead
embeddingModel?: BaseEmbedding | undefined;
embedModel?: BaseEmbedding | undefined;
};
export abstract class BaseVectorStore<Client = unknown, T = unknown> {
@@ -117,7 +119,8 @@ export abstract class BaseVectorStore<Client = unknown, T = unknown> {
): Promise<VectorStoreQueryResult>;
protected constructor(params?: VectorStoreBaseParams) {
this.embedModel = params?.embeddingModel ?? Settings.embedModel;
this.embedModel =
params?.embedModel ?? params?.embeddingModel ?? Settings.embedModel;
}
}
@@ -272,7 +272,7 @@ export class SimpleVectorStore extends BaseVectorStore {
static async fromPersistPath(
persistPath: string,
embeddingModel?: BaseEmbedding,
embedModel?: BaseEmbedding,
): Promise<SimpleVectorStore> {
const dirPath = path.dirname(persistPath);
if (!(await exists(dirPath))) {
@@ -300,20 +300,20 @@ export class SimpleVectorStore extends BaseVectorStore {
data.textIdToRefDocId = dataDict.textIdToRefDocId ?? {};
// @ts-expect-error TS2322
data.metadataDict = dataDict.metadataDict ?? {};
const store = new SimpleVectorStore({ data, embeddingModel });
const store = new SimpleVectorStore({ data, embedModel });
store.persistPath = persistPath;
return store;
}
static fromDict(
saveDict: SimpleVectorStoreData,
embeddingModel?: BaseEmbedding,
embedModel?: BaseEmbedding,
): SimpleVectorStore {
const data = new SimpleVectorStoreData();
data.embeddingDict = saveDict.embeddingDict;
data.textIdToRefDocId = saveDict.textIdToRefDocId;
data.metadataDict = saveDict.metadataDict;
return new SimpleVectorStore({ data, embeddingModel });
return new SimpleVectorStore({ data, embedModel });
}
toDict(): SimpleVectorStoreData {
@@ -59,7 +59,7 @@ describe("SimpleVectorStore", () => {
}),
];
store = new SimpleVectorStore({
embeddingModel: {} as BaseEmbedding, // Mocking the embedModel
embedModel: {} as BaseEmbedding, // Mocking the embedModel
data: {
embeddingDict: {},
textIdToRefDocId: {},