From 3109de6073b237ee3dcc93afb69345586f3b836d Mon Sep 17 00:00:00 2001
From: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
Date: Mon, 6 Jan 2025 14:59:20 +0100
Subject: [PATCH] feat: Add load options to new tool mode for vector stores
(#12462)
---
.../createVectorStoreNode.test.ts.snap | 234 ++++++++++++++++++
.../shared/createVectorStoreNode.test.ts | 7 +-
.../shared/createVectorStoreNode.ts | 12 +-
3 files changed, 249 insertions(+), 4 deletions(-)
create mode 100644 packages/@n8n/nodes-langchain/nodes/vector_store/shared/__snapshots__/createVectorStoreNode.test.ts.snap
diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/__snapshots__/createVectorStoreNode.test.ts.snap b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/__snapshots__/createVectorStoreNode.test.ts.snap
new file mode 100644
index 0000000000..91da891842
--- /dev/null
+++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/__snapshots__/createVectorStoreNode.test.ts.snap
@@ -0,0 +1,234 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`createVectorStoreNode retrieve mode supplies vector store as data 1`] = `
+{
+ "codex": {
+ "categories": [
+ "AI",
+ ],
+ "resources": {
+ "primaryDocumentation": [
+ {
+ "url": undefined,
+ },
+ ],
+ },
+ "subcategories": {
+ "AI": [
+ "Vector Stores",
+ "Tools",
+ "Root Nodes",
+ ],
+ "Tools": [
+ "Other Tools",
+ ],
+ },
+ },
+ "credentials": undefined,
+ "defaults": {
+ "name": undefined,
+ },
+ "description": undefined,
+ "displayName": undefined,
+ "group": [
+ "transform",
+ ],
+ "icon": undefined,
+ "iconColor": undefined,
+ "inputs": "={{
+ ((parameters) => {
+ const mode = parameters?.mode;
+ const inputs = [{ displayName: "Embedding", type: "ai_embedding", required: true, maxConnections: 1}]
+
+ if (mode === 'retrieve-as-tool') {
+ return inputs;
+ }
+
+ if (['insert', 'load', 'update'].includes(mode)) {
+ inputs.push({ displayName: "", type: "main"})
+ }
+
+ if (['insert'].includes(mode)) {
+ inputs.push({ displayName: "Document", type: "ai_document", required: true, maxConnections: 1})
+ }
+ return inputs
+ })($parameter)
+ }}",
+ "name": "mockConstructor",
+ "outputs": "={{
+ ((parameters) => {
+ const mode = parameters?.mode ?? 'retrieve';
+
+ if (mode === 'retrieve-as-tool') {
+ return [{ displayName: "Tool", type: "ai_tool"}]
+ }
+
+ if (mode === 'retrieve') {
+ return [{ displayName: "Vector Store", type: "ai_vectorStore"}]
+ }
+ return [{ displayName: "", type: "main"}]
+ })($parameter)
+ }}",
+ "properties": [
+ {
+ "default": "retrieve",
+ "displayName": "Operation Mode",
+ "name": "mode",
+ "noDataExpression": true,
+ "options": [
+ {
+ "action": "Get ranked documents from vector store",
+ "description": "Get many ranked documents from vector store for query",
+ "name": "Get Many",
+ "value": "load",
+ },
+ {
+ "action": "Add documents to vector store",
+ "description": "Insert documents into vector store",
+ "name": "Insert Documents",
+ "value": "insert",
+ },
+ {
+ "action": "Retrieve documents for AI processing as Vector Store",
+ "description": "Retrieve documents from vector store to be used as vector store with AI nodes",
+ "name": "Retrieve Documents (As Vector Store for AI Agent)",
+ "outputConnectionType": "ai_vectorStore",
+ "value": "retrieve",
+ },
+ {
+ "action": "Retrieve documents for AI processing as Tool",
+ "description": "Retrieve documents from vector store to be used as tool with AI nodes",
+ "name": "Retrieve Documents (As Tool for AI Agent)",
+ "outputConnectionType": "ai_tool",
+ "value": "retrieve-as-tool",
+ },
+ ],
+ "type": "options",
+ },
+ {
+ "default": "",
+ "displayName": "This node must be connected to a vector store retriever. Insert one",
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "retrieve",
+ ],
+ },
+ },
+ "name": "notice",
+ "type": "notice",
+ "typeOptions": {
+ "containerClass": "ndv-connection-hint-notice",
+ },
+ },
+ {
+ "default": "",
+ "description": "Name of the vector store",
+ "displayName": "Name",
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "retrieve-as-tool",
+ ],
+ },
+ },
+ "name": "toolName",
+ "placeholder": "e.g. company_knowledge_base",
+ "required": true,
+ "type": "string",
+ "validateType": "string-alphanumeric",
+ },
+ {
+ "default": "",
+ "description": "Explain to the LLM what this tool does, a good, specific description would allow LLMs to produce expected results much more often",
+ "displayName": "Description",
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "retrieve-as-tool",
+ ],
+ },
+ },
+ "name": "toolDescription",
+ "placeholder": "e.g. undefined",
+ "required": true,
+ "type": "string",
+ "typeOptions": {
+ "rows": 2,
+ },
+ },
+ {
+ "default": "",
+ "description": "Search prompt to retrieve matching documents from the vector store using similarity-based ranking",
+ "displayName": "Prompt",
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "load",
+ ],
+ },
+ },
+ "name": "prompt",
+ "required": true,
+ "type": "string",
+ },
+ {
+ "default": 4,
+ "description": "Number of top results to fetch from vector store",
+ "displayName": "Limit",
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "load",
+ "retrieve-as-tool",
+ ],
+ },
+ },
+ "name": "topK",
+ "type": "number",
+ },
+ {
+ "default": true,
+ "description": "Whether or not to include document metadata",
+ "displayName": "Include Metadata",
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "load",
+ "retrieve-as-tool",
+ ],
+ },
+ },
+ "name": "includeDocumentMetadata",
+ "type": "boolean",
+ },
+ {
+ "default": "",
+ "description": "ID of an embedding entry",
+ "displayName": "ID",
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "update",
+ ],
+ },
+ },
+ "name": "id",
+ "required": true,
+ "type": "string",
+ },
+ {
+ "displayOptions": {
+ "show": {
+ "mode": [
+ "load",
+ "retrieve-as-tool",
+ ],
+ },
+ },
+ "name": "loadField",
+ },
+ ],
+ "version": 1,
+}
+`;
diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.test.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.test.ts
index 26036dce80..28d15def1e 100644
--- a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.test.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.test.ts
@@ -49,7 +49,11 @@ describe('createVectorStoreNode', () => {
const vectorStoreNodeArgs = mock({
sharedFields: [],
insertFields: [],
- loadFields: [],
+ loadFields: [
+ {
+ name: 'loadField',
+ },
+ ],
retrieveFields: [],
updateFields: [],
getVectorStoreClient: jest.fn().mockReturnValue(vectorStore),
@@ -82,6 +86,7 @@ describe('createVectorStoreNode', () => {
const wrappedVectorStore = (data.response as { logWrapped: VectorStore }).logWrapped;
// ASSERT
+ expect(nodeType.description).toMatchSnapshot();
expect(wrappedVectorStore).toEqual(vectorStore);
expect(vectorStoreNodeArgs.getVectorStoreClient).toHaveBeenCalled();
});
diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts
index b7c0de3922..f8e11cadf1 100644
--- a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts
@@ -80,10 +80,13 @@ export interface VectorStoreNodeConstructorArgs {
) => Promise;
}
-function transformDescriptionForOperationMode(fields: INodeProperties[], mode: NodeOperationMode) {
+function transformDescriptionForOperationMode(
+ fields: INodeProperties[],
+ mode: NodeOperationMode | NodeOperationMode[],
+) {
return fields.map((field) => ({
...field,
- displayOptions: { show: { mode: [mode] } },
+ displayOptions: { show: { mode: Array.isArray(mode) ? mode : [mode] } },
}));
}
@@ -299,7 +302,10 @@ export const createVectorStoreNode = (args: VectorStoreNodeConstructorArgs) =>
},
},
},
- ...transformDescriptionForOperationMode(args.loadFields ?? [], 'load'),
+ ...transformDescriptionForOperationMode(args.loadFields ?? [], [
+ 'load',
+ 'retrieve-as-tool',
+ ]),
...transformDescriptionForOperationMode(args.retrieveFields ?? [], 'retrieve'),
...transformDescriptionForOperationMode(args.updateFields ?? [], 'update'),
],