From 40ade151724f4af28a6ed959fd9363450ea711fd Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 12:07:01 +0100 Subject: [PATCH] fix(In-Memory Vector Store Node): Fix displaying execution data of connected embedding nodes (#11701) --- .../VectorStoreInMemory.node.ts | 2 +- .../shared/MemoryVectorStoreManager.test.ts | 44 +++++++++++++++++++ .../shared/MemoryVectorStoreManager.ts | 9 ++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.test.ts diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreInMemory/VectorStoreInMemory.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreInMemory/VectorStoreInMemory.node.ts index cbd2cef75a..5508f957f8 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreInMemory/VectorStoreInMemory.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreInMemory/VectorStoreInMemory.node.ts @@ -54,6 +54,6 @@ export class VectorStoreInMemory extends createVectorStoreNode({ const workflowId = context.getWorkflow().id; const vectorStoreInstance = MemoryVectorStoreManager.getInstance(embeddings); - void vectorStoreInstance.addDocuments(`${workflowId}__${memoryKey}`, documents, clearStore); + await vectorStoreInstance.addDocuments(`${workflowId}__${memoryKey}`, documents, clearStore); }, }) {} diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.test.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.test.ts new file mode 100644 index 0000000000..6229868f32 --- /dev/null +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.test.ts @@ -0,0 +1,44 @@ +import type { OpenAIEmbeddings } from '@langchain/openai'; + +import { MemoryVectorStoreManager } from './MemoryVectorStoreManager'; +import { mock } from 'jest-mock-extended'; + +describe('MemoryVectorStoreManager', () => { + it('should create an instance of MemoryVectorStoreManager', () => { + const embeddings = mock(); + + const instance = MemoryVectorStoreManager.getInstance(embeddings); + expect(instance).toBeInstanceOf(MemoryVectorStoreManager); + }); + + it('should return existing instance', () => { + const embeddings = mock(); + + const instance1 = MemoryVectorStoreManager.getInstance(embeddings); + const instance2 = MemoryVectorStoreManager.getInstance(embeddings); + expect(instance1).toBe(instance2); + }); + + it('should update embeddings in existing instance', () => { + const embeddings1 = mock(); + const embeddings2 = mock(); + + const instance = MemoryVectorStoreManager.getInstance(embeddings1); + MemoryVectorStoreManager.getInstance(embeddings2); + + expect((instance as any).embeddings).toBe(embeddings2); + }); + + it('should update embeddings in existing vector store instances', async () => { + const embeddings1 = mock(); + const embeddings2 = mock(); + + const instance1 = MemoryVectorStoreManager.getInstance(embeddings1); + await instance1.getVectorStore('test'); + + const instance2 = MemoryVectorStoreManager.getInstance(embeddings2); + const vectorStoreInstance2 = await instance2.getVectorStore('test'); + + expect((vectorStoreInstance2 as any).embeddings).toBe(embeddings2); + }); +}); diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.ts index 1076fb93ba..5c507a5196 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/MemoryVectorStoreManager.ts @@ -14,7 +14,16 @@ export class MemoryVectorStoreManager { public static getInstance(embeddings: Embeddings): MemoryVectorStoreManager { if (!MemoryVectorStoreManager.instance) { MemoryVectorStoreManager.instance = new MemoryVectorStoreManager(embeddings); + } else { + // We need to update the embeddings in the existing instance. + // This is important as embeddings instance is wrapped in a logWrapper, + // which relies on supplyDataFunctions context which changes on each workflow run + MemoryVectorStoreManager.instance.embeddings = embeddings; + MemoryVectorStoreManager.instance.vectorStoreBuffer.forEach((vectorStoreInstance) => { + vectorStoreInstance.embeddings = embeddings; + }); } + return MemoryVectorStoreManager.instance; }