From 4f8ff36d3bd39b777c6a1270c0d26acc90c05d80 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Tue, 21 Nov 2023 13:54:25 +0200 Subject: [PATCH 01/16] :zap: fixes --- .../Agent/agents/SqlAgent/description.ts | 4 +- .../MemoryBufferWindow.node.ts | 2 +- .../OutputParserAutofixing.node.ts | 7 +++ .../RetrieverVectorStore.node.ts | 4 +- .../nodes-langchain/utils/sharedFields.ts | 46 ++++++++++++------- .../src/components/WorkflowLMChat.vue | 4 +- 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/SqlAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/SqlAgent/description.ts index fdcbfaea2caff..9b6180a8c2818 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/SqlAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/SqlAgent/description.ts @@ -103,11 +103,11 @@ export const sqlAgentAgentProperties: INodeProperties[] = [ }, }, { - displayName: 'Top K', + displayName: 'Limit', name: 'topK', type: 'number', default: 10, - description: 'Number of top results agent should return', + description: 'The maximum number of results to return', }, ], }, diff --git a/packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts b/packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts index 3732a4bd5ac9a..7b72321b37550 100644 --- a/packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.ts @@ -71,7 +71,7 @@ export class MemoryBufferWindow implements INodeType { icon: 'fa:database', group: ['transform'], version: 1, - description: 'Stores the chat history in a windowed buffer. Refreshes on restart.', + description: 'Stores in n8n memory, so no credentials required', defaults: { name: 'Window Buffer Memory', }, diff --git a/packages/@n8n/nodes-langchain/nodes/output_parser/OutputParserAutofixing/OutputParserAutofixing.node.ts b/packages/@n8n/nodes-langchain/nodes/output_parser/OutputParserAutofixing/OutputParserAutofixing.node.ts index b16a969b26c34..0e495913481ee 100644 --- a/packages/@n8n/nodes-langchain/nodes/output_parser/OutputParserAutofixing/OutputParserAutofixing.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/output_parser/OutputParserAutofixing/OutputParserAutofixing.node.ts @@ -56,6 +56,13 @@ export class OutputParserAutofixing implements INodeType { outputs: [NodeConnectionType.AiOutputParser], outputNames: ['Output Parser'], properties: [ + { + displayName: + 'This node wraps another output parser. If the first one fails it calls an LLM to fix the format', + name: 'info', + type: 'notice', + default: '', + }, getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]), ], }; diff --git a/packages/@n8n/nodes-langchain/nodes/retrievers/RetrieverVectorStore/RetrieverVectorStore.node.ts b/packages/@n8n/nodes-langchain/nodes/retrievers/RetrieverVectorStore/RetrieverVectorStore.node.ts index 2bcc387dc9458..92a33538afc09 100644 --- a/packages/@n8n/nodes-langchain/nodes/retrievers/RetrieverVectorStore/RetrieverVectorStore.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/retrievers/RetrieverVectorStore/RetrieverVectorStore.node.ts @@ -47,11 +47,11 @@ export class RetrieverVectorStore implements INodeType { outputNames: ['Retriever'], properties: [ { - displayName: 'Top K', + displayName: 'Limit', name: 'topK', type: 'number', default: 4, - description: 'Number of top results to fetch from vector store', + description: 'The maximum number of results to return', }, ], }; diff --git a/packages/@n8n/nodes-langchain/utils/sharedFields.ts b/packages/@n8n/nodes-langchain/utils/sharedFields.ts index 858583b9d7581..4a22829a0c8df 100644 --- a/packages/@n8n/nodes-langchain/utils/sharedFields.ts +++ b/packages/@n8n/nodes-langchain/utils/sharedFields.ts @@ -101,24 +101,36 @@ export function getConnectionHintNoticeField( groupedConnections.get(connectionString)?.push(localeString); }); - const ahrefs = Array.from(groupedConnections, ([connection, locales]) => { - // If there are multiple locales, join them with ' or ' - // use determineArticle to insert the correct article - const locale = - locales.length > 1 - ? locales - .map((localeString, index, { length }) => { - return ( - (index === 0 ? `${determineArticle(localeString)} ` : '') + - (index < length - 1 ? `${localeString} or ` : localeString) - ); - }) - .join('') - : `${determineArticle(locales[0])} ${locales[0]}`; - return getAhref({ connection, locale }); - }); + let displayName; + + if (groupedConnections.size === 1) { + const [[connection, locales]] = Array.from(groupedConnections); + displayName = `This node must be connected to ${determineArticle( + locales[0], + )} ${locales[0].toLowerCase()}. Insert one`; + } else { + const ahrefs = Array.from(groupedConnections, ([connection, locales]) => { + // If there are multiple locales, join them with ' or ' + // use determineArticle to insert the correct article + const locale = + locales.length > 1 + ? locales + .map((localeString, index, { length }) => { + return ( + (index === 0 ? `${determineArticle(localeString)} ` : '') + + (index < length - 1 ? `${localeString} or ` : localeString) + ); + }) + .join('') + : `${determineArticle(locales[0])} ${locales[0]}`; + return getAhref({ connection, locale }); + }); + + displayName = `This node needs to be connected to ${ahrefs.join(' or ')}.`; + } + return { - displayName: `This node needs to be connected to ${ahrefs.join(' or ')}.`, + displayName, name: 'notice', type: 'notice', default: '', diff --git a/packages/editor-ui/src/components/WorkflowLMChat.vue b/packages/editor-ui/src/components/WorkflowLMChat.vue index 71ceb4ce5acd3..2280cfeacf0f8 100644 --- a/packages/editor-ui/src/components/WorkflowLMChat.vue +++ b/packages/editor-ui/src/components/WorkflowLMChat.vue @@ -286,8 +286,8 @@ export default defineComponent({ if (!chatNode) { this.showError( - new Error('Chat viable node(Agent or Chain) could not be found!'), - 'Chat node not found', + new Error('Missing AI node'), + 'Chat only works when an AI agent or chain is connected to the chat trigger node', ); return; } From d95599a5c4f5bc15eedc87caac4bcbb5e0377730 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Wed, 22 Nov 2023 08:25:44 +0200 Subject: [PATCH 02/16] :zap: chat output property renamed, output panel UI update --- .../Agent/agents/ConversationalAgent/description.ts | 2 +- .../Agent/agents/OpenAiFunctionsAgent/description.ts | 2 +- .../Agent/agents/PlanAndExecuteAgent/description.ts | 2 +- .../agents/Agent/agents/ReActAgent/description.ts | 2 +- .../nodes/chains/ChainLLM/ChainLlm.node.ts | 2 +- .../chains/ChainRetrievalQA/ChainRetrievalQa.node.ts | 2 +- .../ManualChatTrigger/ManualChatTrigger.node.ts | 2 +- packages/editor-ui/src/components/OutputPanel.vue | 7 ------- packages/editor-ui/src/components/RunData.vue | 2 +- packages/editor-ui/src/components/WorkflowLMChat.vue | 10 +++++++--- packages/editor-ui/src/plugins/i18n/locales/en.json | 2 +- 11 files changed, 16 insertions(+), 19 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts index 027746d44a8ef..5c7efd81c34f6 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts @@ -12,7 +12,7 @@ export const conversationalAgentProperties: INodeProperties[] = [ agent: ['conversationalAgent'], }, }, - default: '={{ $json.input }}', + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts index 5bcb020d87945..5212ac7624673 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts @@ -12,7 +12,7 @@ export const openAiFunctionsAgentProperties: INodeProperties[] = [ agent: ['openAiFunctionsAgent'], }, }, - default: '={{ $json.input }}', + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts index 51879ad71504c..17ab35a6df5ce 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts @@ -12,7 +12,7 @@ export const planAndExecuteAgentProperties: INodeProperties[] = [ agent: ['planAndExecuteAgent'], }, }, - default: '={{ $json.input }}', + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts index 44340fa25eebd..944146da2139f 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts @@ -12,7 +12,7 @@ export const reActAgentAgentProperties: INodeProperties[] = [ agent: ['reActAgent'], }, }, - default: '={{ $json.input }}', + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts b/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts index 91c067bfcd6fe..679a7d233ce3b 100644 --- a/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts @@ -230,7 +230,7 @@ export class ChainLlm implements INodeType { name: 'prompt', type: 'string', required: true, - default: '={{ $json.input }}', + default: '={{ $json.chat_input }}', }, { displayName: 'Chat Messages (if Using a Chat Model)', diff --git a/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts b/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts index 8c8770cedf36e..1ac4ff324722e 100644 --- a/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts @@ -63,7 +63,7 @@ export class ChainRetrievalQa implements INodeType { name: 'query', type: 'string', required: true, - default: '={{ $json.input }}', + default: '={{ $json.chat_input }}', }, ], }; diff --git a/packages/@n8n/nodes-langchain/nodes/trigger/ManualChatTrigger/ManualChatTrigger.node.ts b/packages/@n8n/nodes-langchain/nodes/trigger/ManualChatTrigger/ManualChatTrigger.node.ts index 9dac04e3baf61..dde9cbda7db70 100644 --- a/packages/@n8n/nodes-langchain/nodes/trigger/ManualChatTrigger/ManualChatTrigger.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/trigger/ManualChatTrigger/ManualChatTrigger.node.ts @@ -12,7 +12,7 @@ export class ManualChatTrigger implements INodeType { name: 'manualChatTrigger', icon: 'fa:comments', group: ['trigger'], - version: 1, + version: [1, 1.1], description: 'Runs the flow on new manual chat message', eventTriggerDescription: '', maxNodes: 1, diff --git a/packages/editor-ui/src/components/OutputPanel.vue b/packages/editor-ui/src/components/OutputPanel.vue index ac8c83832a1e2..e091d796799bd 100644 --- a/packages/editor-ui/src/components/OutputPanel.vue +++ b/packages/editor-ui/src/components/OutputPanel.vue @@ -66,13 +66,6 @@ }} {{ $locale.baseText('ndv.output.runNodeHint') }} - -
- {{ $locale.baseText('generic.or') }} - - {{ $locale.baseText('ndv.output.insertTestData') }} - -
diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 43ed2b71432db..a2ee82a6f0a17 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -57,7 +57,7 @@ @update:modelValue="onDisplayModeChange" /> Execute node again to refresh output.", "ndv.output.staleDataWarning.pinData": "Node parameter changes will not affect pinned output data.", From 4b88a887e8dade06c23aefe7759bb8c7c86c314c Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Thu, 23 Nov 2023 05:59:12 +0200 Subject: [PATCH 03/16] :zap: rlc for pinecone index --- .../VectorStorePinecone.node.ts | 13 +++------- .../VectorStorePineconeInsert.node.ts | 16 ++++++------ .../VectorStorePineconeLoad.node.ts | 16 ++++++------ .../shared/createVectorStoreNode.ts | 13 ++++++++++ .../nodes/vector_store/shared/descriptions.ts | 25 +++++++++++++++++++ .../vector_store/shared/methods/listSearch.ts | 20 +++++++++++++++ 6 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts create mode 100644 packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts index 8413068a1176c..9d2debaa11c44 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts @@ -4,16 +4,10 @@ import { PineconeStore } from 'langchain/vectorstores/pinecone'; import { Pinecone } from '@pinecone-database/pinecone'; import { createVectorStoreNode } from '../shared/createVectorStoreNode'; import { metadataFilterField } from '../../../utils/sharedFields'; +import { pineconeIndexRLC } from '../shared/descriptions'; +import { pineconeIndexSearch } from '../shared/methods/listSearch'; -const sharedFields: INodeProperties[] = [ - { - displayName: 'Pinecone Index', - name: 'pineconeIndex', - type: 'string', - default: '', - required: true, - }, -]; +const sharedFields: INodeProperties[] = [pineconeIndexRLC]; const retrieveFields: INodeProperties[] = [ { @@ -77,6 +71,7 @@ export const VectorStorePinecone = createVectorStoreNode({ }, ], }, + methods: { listSearch: { pineconeIndexSearch } }, retrieveFields, loadFields: retrieveFields, insertFields, diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts index b74562a695f74..ecaadac3eee65 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts @@ -11,6 +11,8 @@ import type { Embeddings } from 'langchain/embeddings/base'; import type { Document } from 'langchain/document'; import type { N8nJsonLoader } from '../../../utils/N8nJsonLoader'; import { processDocuments } from '../shared/processDocuments'; +import { pineconeIndexRLC } from '../shared/descriptions'; +import { pineconeIndexSearch } from '../shared/methods/listSearch'; // This node is deprecated. Use VectorStorePinecone instead. export class VectorStorePineconeInsert implements INodeType { @@ -63,13 +65,7 @@ export class VectorStorePineconeInsert implements INodeType { ], outputs: [NodeConnectionType.Main], properties: [ - { - displayName: 'Pinecone Index', - name: 'pineconeIndex', - type: 'string', - default: '', - required: true, - }, + pineconeIndexRLC, { displayName: 'Pinecone Namespace', name: 'pineconeNamespace', @@ -92,6 +88,12 @@ export class VectorStorePineconeInsert implements INodeType { ], }; + methods = { + listSearch: { + pineconeIndexSearch, + }, + }; + async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(0); this.logger.verbose('Executing data for Pinecone Insert Vector Store'); diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts index bce5f532858e3..f76ebe4f494df 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts @@ -12,6 +12,8 @@ import type { Embeddings } from 'langchain/embeddings/base'; import { logWrapper } from '../../../utils/logWrapper'; import { metadataFilterField } from '../../../utils/sharedFields'; import { getMetadataFiltersValues } from '../../../utils/helpers'; +import { pineconeIndexRLC } from '../shared/descriptions'; +import { pineconeIndexSearch } from '../shared/methods/listSearch'; // This node is deprecated. Use VectorStorePinecone instead. export class VectorStorePineconeLoad implements INodeType { @@ -57,13 +59,7 @@ export class VectorStorePineconeLoad implements INodeType { outputs: [NodeConnectionType.AiVectorStore], outputNames: ['Vector Store'], properties: [ - { - displayName: 'Pinecone Index', - name: 'pineconeIndex', - type: 'string', - default: '', - required: true, - }, + pineconeIndexRLC, { displayName: 'Pinecone Namespace', name: 'pineconeNamespace', @@ -81,6 +77,12 @@ export class VectorStorePineconeLoad implements INodeType { ], }; + methods = { + listSearch: { + pineconeIndexSearch, + }, + }; + async supplyData(this: IExecuteFunctions, itemIndex: number): Promise { this.logger.verbose('Supplying data for Pinecone Load Vector Store'); 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 981f662a74493..32a71541c4354 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts @@ -10,6 +10,8 @@ import type { INodeTypeDescription, SupplyData, INodeType, + ILoadOptionsFunctions, + INodeListSearchResult, } from 'n8n-workflow'; import type { Embeddings } from 'langchain/embeddings/base'; import type { Document } from 'langchain/document'; @@ -30,6 +32,15 @@ interface NodeMeta { } interface VectorStoreNodeConstructorArgs { meta: NodeMeta; + methods?: { + listSearch?: { + [key: string]: ( + this: ILoadOptionsFunctions, + filter?: string, + paginationToken?: string, + ) => Promise; + }; + }; sharedFields: INodeProperties[]; insertFields?: INodeProperties[]; loadFields?: INodeProperties[]; @@ -178,6 +189,8 @@ export const createVectorStoreNode = (args: VectorStoreNodeConstructorArgs) => ], }; + methods = args.methods; + async execute(this: IExecuteFunctions): Promise { const mode = this.getNodeParameter('mode', 0) as 'load' | 'insert' | 'retrieve'; diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts new file mode 100644 index 0000000000000..752019dac9c99 --- /dev/null +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts @@ -0,0 +1,25 @@ +import type { INodeProperties } from 'n8n-workflow'; + +export const pineconeIndexRLC: INodeProperties = { + displayName: 'Pinecone Index', + name: 'pineconeIndex', + type: 'resourceLocator', + default: { mode: 'list', value: '' }, + required: true, + modes: [ + { + displayName: 'From List', + name: 'list', + type: 'list', + typeOptions: { + searchListMethod: 'pineconeIndexSearch', + searchable: true, + }, + }, + { + displayName: 'ID', + name: 'id', + type: 'string', + }, + ], +}; diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts new file mode 100644 index 0000000000000..73d08035f4399 --- /dev/null +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts @@ -0,0 +1,20 @@ +import type { ILoadOptionsFunctions } from 'n8n-workflow'; +import { Pinecone } from '@pinecone-database/pinecone'; + +export async function pineconeIndexSearch(this: ILoadOptionsFunctions) { + const credentials = await this.getCredentials('pineconeApi'); + + const client = new Pinecone({ + apiKey: credentials.apiKey as string, + environment: credentials.environment as string, + }); + + const indexes = await client.listIndexes(); + + const results = indexes.map((index) => ({ + name: index.name, + value: index.name, + })); + + return { results }; +} From cc9ec9ca9b07d5118fedcca3228fd192d6de8219 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Thu, 23 Nov 2023 06:39:04 +0200 Subject: [PATCH 04/16] :zap: pinecone credentials test --- .../credentials/PineconeApi.credentials.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/@n8n/nodes-langchain/credentials/PineconeApi.credentials.ts b/packages/@n8n/nodes-langchain/credentials/PineconeApi.credentials.ts index c431abda52718..a4f0be5e9c659 100644 --- a/packages/@n8n/nodes-langchain/credentials/PineconeApi.credentials.ts +++ b/packages/@n8n/nodes-langchain/credentials/PineconeApi.credentials.ts @@ -1,6 +1,6 @@ import type { IAuthenticateGeneric, - // ICredentialTestRequest, + ICredentialTestRequest, ICredentialType, INodeProperties, } from 'n8n-workflow'; @@ -38,4 +38,13 @@ export class PineconeApi implements ICredentialType { }, }, }; + + test: ICredentialTestRequest = { + request: { + baseURL: '=https://controller.{{$credentials.environment}}.pinecone.io/databases', + headers: { + accept: 'application/json; charset=utf-8', + }, + }, + }; } From 86cd05385b72678cbcccc5ae44f557af070ed08e Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Thu, 23 Nov 2023 07:12:12 +0200 Subject: [PATCH 05/16] :zap: supabase table name rlc --- .../VectorStoreSupabase.node.ts | 16 ++++------ .../VectorStoreSupabaseInsert.node.ts | 13 ++++----- .../VectorStoreSupabaseLoad.node.ts | 13 ++++----- .../nodes/vector_store/shared/descriptions.ts | 24 ++++++++++++++- .../vector_store/shared/methods/listSearch.ts | 29 ++++++++++++++++++- 5 files changed, 67 insertions(+), 28 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts index 4a69fbcdaacf3..38c33c7ff470e 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts @@ -3,17 +3,10 @@ import { createClient } from '@supabase/supabase-js'; import { SupabaseVectorStore } from 'langchain/vectorstores/supabase'; import { createVectorStoreNode } from '../shared/createVectorStoreNode'; import { metadataFilterField } from '../../../utils/sharedFields'; +import { supabaseTableNameRLC } from '../shared/descriptions'; +import { supabaseTableNameSearch } from '../shared/methods/listSearch'; -const sharedFields: INodeProperties[] = [ - { - displayName: 'Table Name', - name: 'tableName', - type: 'string', - default: '', - required: true, - description: 'Name of the table to load from', - }, -]; +const sharedFields: INodeProperties[] = [supabaseTableNameRLC]; const insertFields: INodeProperties[] = [ { displayName: 'Options', @@ -66,6 +59,9 @@ export const VectorStoreSupabase = createVectorStoreNode({ }, ], }, + methods: { + listSearch: { supabaseTableNameSearch }, + }, sharedFields, insertFields, loadFields: retrieveFields, diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts index c08f5101f2f72..d29679f15689b 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts @@ -12,6 +12,8 @@ import { SupabaseVectorStore } from 'langchain/vectorstores/supabase'; import type { N8nJsonLoader } from '../../../utils/N8nJsonLoader'; import { processDocuments } from '../shared/processDocuments'; +import { supabaseTableNameRLC } from '../shared/descriptions'; +import { supabaseTableNameSearch } from '../shared/methods/listSearch'; // This node is deprecated. Use VectorStoreSupabase instead. export class VectorStoreSupabaseInsert implements INodeType { @@ -71,14 +73,7 @@ export class VectorStoreSupabaseInsert implements INodeType { type: 'notice', default: '', }, - { - displayName: 'Table Name', - name: 'tableName', - type: 'string', - default: '', - required: true, - description: 'Name of the table to insert into', - }, + supabaseTableNameRLC, { displayName: 'Query Name', name: 'queryName', @@ -96,6 +91,8 @@ export class VectorStoreSupabaseInsert implements INodeType { ], }; + methods = { listSearch: { supabaseTableNameSearch } }; + async execute(this: IExecuteFunctions): Promise { this.logger.verbose('Executing data for Supabase Insert Vector Store'); diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts index add4a7dceabd3..e1b86a5178f75 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts @@ -12,6 +12,8 @@ import { SupabaseVectorStore } from 'langchain/vectorstores/supabase'; import { logWrapper } from '../../../utils/logWrapper'; import { metadataFilterField } from '../../../utils/sharedFields'; import { getMetadataFiltersValues } from '../../../utils/helpers'; +import { supabaseTableNameRLC } from '../shared/descriptions'; +import { supabaseTableNameSearch } from '../shared/methods/listSearch'; // This node is deprecated. Use VectorStoreSupabase instead. export class VectorStoreSupabaseLoad implements INodeType { @@ -57,14 +59,7 @@ export class VectorStoreSupabaseLoad implements INodeType { outputs: [NodeConnectionType.AiVectorStore], outputNames: ['Vector Store'], properties: [ - { - displayName: 'Table Name', - name: 'tableName', - type: 'string', - default: '', - required: true, - description: 'Name of the table to load from', - }, + supabaseTableNameRLC, { displayName: 'Query Name', name: 'queryName', @@ -84,6 +79,8 @@ export class VectorStoreSupabaseLoad implements INodeType { ], }; + methods = { listSearch: { supabaseTableNameSearch } }; + async supplyData(this: IExecuteFunctions, itemIndex: number): Promise { this.logger.verbose('Supply Supabase Load Vector Store'); diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts index 752019dac9c99..573044b922ece 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/descriptions.ts @@ -13,7 +13,29 @@ export const pineconeIndexRLC: INodeProperties = { type: 'list', typeOptions: { searchListMethod: 'pineconeIndexSearch', - searchable: true, + }, + }, + { + displayName: 'ID', + name: 'id', + type: 'string', + }, + ], +}; + +export const supabaseTableNameRLC: INodeProperties = { + displayName: 'Table Name', + name: 'tableName', + type: 'resourceLocator', + default: { mode: 'list', value: '' }, + required: true, + modes: [ + { + displayName: 'From List', + name: 'list', + type: 'list', + typeOptions: { + searchListMethod: 'supabaseTableNameSearch', }, }, { diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts index 73d08035f4399..a3b3ddda3e58a 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/methods/listSearch.ts @@ -1,4 +1,4 @@ -import type { ILoadOptionsFunctions } from 'n8n-workflow'; +import type { IDataObject, ILoadOptionsFunctions } from 'n8n-workflow'; import { Pinecone } from '@pinecone-database/pinecone'; export async function pineconeIndexSearch(this: ILoadOptionsFunctions) { @@ -18,3 +18,30 @@ export async function pineconeIndexSearch(this: ILoadOptionsFunctions) { return { results }; } + +export async function supabaseTableNameSearch(this: ILoadOptionsFunctions) { + const credentials = await this.getCredentials('supabaseApi'); + + const results = []; + + const { paths } = await this.helpers.requestWithAuthentication.call(this, 'supabaseApi', { + headers: { + Prefer: 'return=representation', + }, + method: 'GET', + uri: `${credentials.host}/rest/v1/`, + json: true, + }); + + for (const path of Object.keys(paths as IDataObject)) { + //omit introspection path + if (path === '/') continue; + + results.push({ + name: path.replace('/', ''), + value: path.replace('/', ''), + }); + } + + return { results }; +} From d8ec941add34d4f6ccb87d3245d1ea92bb335cda Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Thu, 23 Nov 2023 09:02:34 +0200 Subject: [PATCH 06/16] :zap: openAi llm model rlc --- .../nodes/llms/LMOpenAi/LmOpenAi.node.ts | 107 ++++++++++-------- .../VectorStorePinecone.node.ts | 8 +- .../VectorStorePineconeInsert.node.ts | 2 +- .../VectorStorePineconeLoad.node.ts | 4 +- .../VectorStoreSupabase.node.ts | 8 +- .../VectorStoreSupabaseInsert.node.ts | 2 +- .../VectorStoreSupabaseLoad.node.ts | 4 +- 7 files changed, 81 insertions(+), 54 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts b/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts index e9e41601e6fde..a1ff2e3854cd2 100644 --- a/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts @@ -1,10 +1,12 @@ /* eslint-disable n8n-nodes-base/node-dirname-against-convention */ -import { - NodeConnectionType, - type IExecuteFunctions, - type INodeType, - type INodeTypeDescription, - type SupplyData, +import { NodeConnectionType } from 'n8n-workflow'; +import type { + IExecuteFunctions, + INodeType, + INodeTypeDescription, + SupplyData, + IDataObject, + ILoadOptionsFunctions, } from 'n8n-workflow'; import type { ClientOptions } from 'openai'; @@ -58,55 +60,33 @@ export class LmOpenAi implements INodeType { { displayName: 'Model', name: 'model', - type: 'options', + type: 'resourceLocator', + default: { mode: 'list', value: 'gpt-3.5-turbo-instruct' }, + required: true, description: 'The model which will generate the completion. Learn more.', - typeOptions: { - loadOptions: { - routing: { - request: { - method: 'GET', - url: '={{ $parameter.options?.baseURL?.split("/").slice(-1).pop() || "v1" }}/models', - }, - output: { - postReceive: [ - { - type: 'rootProperty', - properties: { - property: 'data', - }, - }, - { - type: 'filter', - properties: { - pass: "={{$responseItem.owned_by.startsWith('system')", - }, - }, - { - type: 'setKeyValue', - properties: { - name: '={{$responseItem.id}}', - value: '={{$responseItem.id}}', - }, - }, - { - type: 'sort', - properties: { - key: 'name', - }, - }, - ], - }, + modes: [ + { + displayName: 'From List', + name: 'list', + type: 'list', + typeOptions: { + searchListMethod: 'openAiModelSearch', }, }, - }, + { + displayName: 'ID', + name: 'id', + type: 'string', + }, + ], routing: { send: { type: 'body', property: 'model', + value: '={{$parameter.model.value}}', }, }, - default: 'gpt-3.5-turbo-instruct', }, { displayName: 'Options', @@ -189,10 +169,45 @@ export class LmOpenAi implements INodeType { ], }; + methods = { + listSearch: { + async openAiModelSearch(this: ILoadOptionsFunctions) { + const results = []; + + const options = this.getNodeParameter('options', {}) as IDataObject; + + let uri = 'https://api.openai.com/v1/models'; + + if (options.baseURL) { + uri = `${options.baseURL}/models`; + } + + const { data } = await this.helpers.requestWithAuthentication.call(this, 'openAiApi', { + method: 'GET', + uri, + json: true, + }); + + for (const model of data as IDataObject[]) { + if (!(model.owned_by as string)?.startsWith('system')) continue; + results.push({ + name: model.id as string, + value: model.id as string, + }); + } + + return { results }; + }, + }, + }; + async supplyData(this: IExecuteFunctions, itemIndex: number): Promise { const credentials = await this.getCredentials('openAiApi'); - const modelName = this.getNodeParameter('model', itemIndex) as string; + const modelName = this.getNodeParameter('model', itemIndex, '', { + extractValue: true, + }) as string; + const options = this.getNodeParameter('options', itemIndex, {}) as { baseURL?: string; frequencyPenalty?: number; diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts index 9d2debaa11c44..6d2fe912dd69e 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts @@ -77,7 +77,9 @@ export const VectorStorePinecone = createVectorStoreNode({ insertFields, sharedFields, async getVectorStoreClient(context, filter, embeddings, itemIndex) { - const index = context.getNodeParameter('pineconeIndex', itemIndex) as string; + const index = context.getNodeParameter('pineconeIndex', itemIndex, '', { + extractValue: true, + }) as string; const options = context.getNodeParameter('options', itemIndex, {}) as { pineconeNamespace?: string; }; @@ -98,7 +100,9 @@ export const VectorStorePinecone = createVectorStoreNode({ return PineconeStore.fromExistingIndex(embeddings, config); }, async populateVectorStore(context, embeddings, documents, itemIndex) { - const index = context.getNodeParameter('pineconeIndex', itemIndex) as string; + const index = context.getNodeParameter('pineconeIndex', itemIndex, '', { + extractValue: true, + }) as string; const options = context.getNodeParameter('options', itemIndex, {}) as { pineconeNamespace?: string; clearNamespace?: boolean; diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts index ecaadac3eee65..342b5ef725e90 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.ts @@ -99,7 +99,7 @@ export class VectorStorePineconeInsert implements INodeType { this.logger.verbose('Executing data for Pinecone Insert Vector Store'); const namespace = this.getNodeParameter('pineconeNamespace', 0) as string; - const index = this.getNodeParameter('pineconeIndex', 0) as string; + const index = this.getNodeParameter('pineconeIndex', 0, '', { extractValue: true }) as string; const clearNamespace = this.getNodeParameter('clearNamespace', 0) as boolean; const credentials = await this.getCredentials('pineconeApi'); diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts index f76ebe4f494df..50ff8b407de49 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.ts @@ -87,7 +87,9 @@ export class VectorStorePineconeLoad implements INodeType { this.logger.verbose('Supplying data for Pinecone Load Vector Store'); const namespace = this.getNodeParameter('pineconeNamespace', itemIndex) as string; - const index = this.getNodeParameter('pineconeIndex', itemIndex) as string; + const index = this.getNodeParameter('pineconeIndex', itemIndex, '', { + extractValue: true, + }) as string; const credentials = await this.getCredentials('pineconeApi'); const embeddings = (await this.getInputConnectionData( diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts index 38c33c7ff470e..c26128e564dff 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts @@ -67,7 +67,9 @@ export const VectorStoreSupabase = createVectorStoreNode({ loadFields: retrieveFields, retrieveFields, async getVectorStoreClient(context, filter, embeddings, itemIndex) { - const tableName = context.getNodeParameter('tableName', itemIndex) as string; + const tableName = context.getNodeParameter('tableName', itemIndex, '', { + extractValue: true, + }) as string; const options = context.getNodeParameter('options', itemIndex, {}) as { queryName: string; }; @@ -82,7 +84,9 @@ export const VectorStoreSupabase = createVectorStoreNode({ }); }, async populateVectorStore(context, embeddings, documents, itemIndex) { - const tableName = context.getNodeParameter('tableName', itemIndex) as string; + const tableName = context.getNodeParameter('tableName', itemIndex, '', { + extractValue: true, + }) as string; const options = context.getNodeParameter('options', itemIndex, {}) as { queryName: string; }; diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts index d29679f15689b..fd287f625303f 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.ts @@ -97,7 +97,7 @@ export class VectorStoreSupabaseInsert implements INodeType { this.logger.verbose('Executing data for Supabase Insert Vector Store'); const items = this.getInputData(0); - const tableName = this.getNodeParameter('tableName', 0) as string; + const tableName = this.getNodeParameter('tableName', 0, '', { extractValue: true }) as string; const queryName = this.getNodeParameter('queryName', 0) as string; const credentials = await this.getCredentials('supabaseApi'); diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts index e1b86a5178f75..60c031ff66e8a 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.ts @@ -84,7 +84,9 @@ export class VectorStoreSupabaseLoad implements INodeType { async supplyData(this: IExecuteFunctions, itemIndex: number): Promise { this.logger.verbose('Supply Supabase Load Vector Store'); - const tableName = this.getNodeParameter('tableName', itemIndex) as string; + const tableName = this.getNodeParameter('tableName', itemIndex, '', { + extractValue: true, + }) as string; const queryName = this.getNodeParameter('queryName', itemIndex) as string; const credentials = await this.getCredentials('supabaseApi'); From b9ba07968f963865465eafcb70d4afdcef89fb2a Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Fri, 24 Nov 2023 12:33:03 +0200 Subject: [PATCH 07/16] :zap: default expression for input update --- .../agents/Agent/agents/ConversationalAgent/description.ts | 2 +- .../agents/Agent/agents/OpenAiFunctionsAgent/description.ts | 2 +- .../agents/Agent/agents/PlanAndExecuteAgent/description.ts | 2 +- .../nodes/agents/Agent/agents/ReActAgent/description.ts | 2 +- .../@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts | 2 +- .../nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts index 5c7efd81c34f6..5cb74920f1926 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts @@ -12,7 +12,7 @@ export const conversationalAgentProperties: INodeProperties[] = [ agent: ['conversationalAgent'], }, }, - default: '={{ $json.chat_input }}', + default: '={{ $json.chat_input ?? $json.input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts index 5212ac7624673..de16ddf077073 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts @@ -12,7 +12,7 @@ export const openAiFunctionsAgentProperties: INodeProperties[] = [ agent: ['openAiFunctionsAgent'], }, }, - default: '={{ $json.chat_input }}', + default: '={{ $json.chat_input ?? $json.input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts index 17ab35a6df5ce..657b07540d633 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts @@ -12,7 +12,7 @@ export const planAndExecuteAgentProperties: INodeProperties[] = [ agent: ['planAndExecuteAgent'], }, }, - default: '={{ $json.chat_input }}', + default: '={{ $json.chat_input ?? $json.input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts index 944146da2139f..f27fe9a5820bc 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts @@ -12,7 +12,7 @@ export const reActAgentAgentProperties: INodeProperties[] = [ agent: ['reActAgent'], }, }, - default: '={{ $json.chat_input }}', + default: '={{ $json.chat_input ?? $json.input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts b/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts index 2a6109fad2a6a..e4f4d13d5bdf8 100644 --- a/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts @@ -235,7 +235,7 @@ export class ChainLlm implements INodeType { name: 'prompt', type: 'string', required: true, - default: '={{ $json.chat_input }}', + default: '={{ $json.chat_input ?? $json.input }}', }, { displayName: 'Chat Messages (if Using a Chat Model)', diff --git a/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts b/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts index 1ac4ff324722e..7e8662b2002bf 100644 --- a/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts @@ -63,7 +63,7 @@ export class ChainRetrievalQa implements INodeType { name: 'query', type: 'string', required: true, - default: '={{ $json.chat_input }}', + default: '={{ $json.chat_input ?? $json.input }}', }, ], }; From d84f0c6ea9be7d6a6a1d0d8bad009647a7adbb36 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Fri, 24 Nov 2023 13:23:15 +0200 Subject: [PATCH 08/16] :zap: linter fix --- .../editor-ui/src/components/RunDataAi/useAiContentParsers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts b/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts index 3b9a0e017df94..ddcd8b9a4c590 100644 --- a/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts +++ b/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts @@ -93,7 +93,7 @@ const outputTypeParsers: { type: string; image_url?: { url: string; - } + }; } let message = content.kwargs.content; if (Array.isArray(message)) { From fff6d867864bf2a3129c79f8171c818766b32f33 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Fri, 24 Nov 2023 14:41:07 +0200 Subject: [PATCH 09/16] :zap: test fix --- .../src/components/__tests__/WorkflowLMChatModal.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/src/components/__tests__/WorkflowLMChatModal.test.ts b/packages/editor-ui/src/components/__tests__/WorkflowLMChatModal.test.ts index 6d15cab32803a..44c5cb3d63c87 100644 --- a/packages/editor-ui/src/components/__tests__/WorkflowLMChatModal.test.ts +++ b/packages/editor-ui/src/components/__tests__/WorkflowLMChatModal.test.ts @@ -106,7 +106,7 @@ describe('WorkflowLMChatModal', () => { await waitFor(() => expect(document.querySelectorAll('.el-notification')[0]).toHaveTextContent( - 'Chat node not found', + 'Missing AI node Chat only works when an AI agent or chain is connected to the chat trigger node', ), ); }); @@ -121,7 +121,7 @@ describe('WorkflowLMChatModal', () => { await waitFor(() => expect(document.querySelectorAll('.el-notification')[1]).toHaveTextContent( - 'Chat node not found', + 'Missing AI node Chat only works when an AI agent or chain is connected to the chat trigger node', ), ); }); From 4a6d6d5323237ab96795b502e33ff0b29e88421b Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Fri, 24 Nov 2023 15:41:35 +0200 Subject: [PATCH 10/16] :zap: defaults update --- .../nodes/agents/Agent/Agent.node.ts | 2 +- .../agents/ConversationalAgent/description.ts | 16 +++++++++++++- .../OpenAiFunctionsAgent/description.ts | 16 +++++++++++++- .../agents/PlanAndExecuteAgent/description.ts | 16 +++++++++++++- .../Agent/agents/ReActAgent/description.ts | 16 +++++++++++++- .../nodes/chains/ChainLLM/ChainLlm.node.ts | 21 +++++++++++++++++-- .../ChainRetrievalQA/ChainRetrievalQa.node.ts | 21 +++++++++++++++++-- 7 files changed, 99 insertions(+), 9 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/Agent.node.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/Agent.node.ts index b4f52619781c4..72aaa8134685e 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/Agent.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/Agent.node.ts @@ -144,7 +144,7 @@ export class Agent implements INodeType { name: 'agent', icon: 'fa:robot', group: ['transform'], - version: 1, + version: [1, 1.1], description: 'Generates an action plan and executes it. Can use external tools.', subtitle: "={{ { conversationalAgent: 'Conversational Agent', openAiFunctionsAgent: 'OpenAI Functions Agent', reactAgent: 'ReAct Agent', sqlAgent: 'SQL Agent' }[$parameter.agent] }}", diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts index 5cb74920f1926..b65b2fddf2c5c 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/description.ts @@ -10,9 +10,23 @@ export const conversationalAgentProperties: INodeProperties[] = [ displayOptions: { show: { agent: ['conversationalAgent'], + '@version': [1], }, }, - default: '={{ $json.chat_input ?? $json.input }}', + default: '={{ $json.input }}', + }, + { + displayName: 'Text', + name: 'text', + type: 'string', + required: true, + displayOptions: { + show: { + agent: ['conversationalAgent'], + '@version': [1.1], + }, + }, + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts index de16ddf077073..5d7d4cc81bedb 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/description.ts @@ -10,9 +10,23 @@ export const openAiFunctionsAgentProperties: INodeProperties[] = [ displayOptions: { show: { agent: ['openAiFunctionsAgent'], + '@version': [1], }, }, - default: '={{ $json.chat_input ?? $json.input }}', + default: '={{ $json.input }}', + }, + { + displayName: 'Text', + name: 'text', + type: 'string', + required: true, + displayOptions: { + show: { + agent: ['openAiFunctionsAgent'], + '@version': [1.1], + }, + }, + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts index 657b07540d633..b9763a99fc127 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/description.ts @@ -10,9 +10,23 @@ export const planAndExecuteAgentProperties: INodeProperties[] = [ displayOptions: { show: { agent: ['planAndExecuteAgent'], + '@version': [1], }, }, - default: '={{ $json.chat_input ?? $json.input }}', + default: '={{ $json.input }}', + }, + { + displayName: 'Text', + name: 'text', + type: 'string', + required: true, + displayOptions: { + show: { + agent: ['planAndExecuteAgent'], + '@version': [1.1], + }, + }, + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts index f27fe9a5820bc..8c806b005c092 100644 --- a/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts +++ b/packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/description.ts @@ -10,9 +10,23 @@ export const reActAgentAgentProperties: INodeProperties[] = [ displayOptions: { show: { agent: ['reActAgent'], + '@version': [1], }, }, - default: '={{ $json.chat_input ?? $json.input }}', + default: '={{ $json.input }}', + }, + { + displayName: 'Text', + name: 'text', + type: 'string', + required: true, + displayOptions: { + show: { + agent: ['reActAgent'], + '@version': [1.1], + }, + }, + default: '={{ $json.chat_input }}', }, { displayName: 'Options', diff --git a/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts b/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts index a25ad9b0e0548..2fc5912d0bd85 100644 --- a/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/chains/ChainLLM/ChainLlm.node.ts @@ -195,7 +195,7 @@ export class ChainLlm implements INodeType { name: 'chainLlm', icon: 'fa:link', group: ['transform'], - version: 1, + version: [1, 1.1], description: 'A simple chain to prompt a large language model', defaults: { name: 'Basic LLM Chain', @@ -239,7 +239,24 @@ export class ChainLlm implements INodeType { name: 'prompt', type: 'string', required: true, - default: '={{ $json.chat_input ?? $json.input }}', + default: '={{ $json.input }}', + displayOptions: { + show: { + '@version': [1], + }, + }, + }, + { + displayName: 'Prompt', + name: 'prompt', + type: 'string', + required: true, + default: '={{ $json.chat_input }}', + displayOptions: { + show: { + '@version': [1.1], + }, + }, }, { displayName: 'Chat Messages (if Using a Chat Model)', diff --git a/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts b/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts index 7e8662b2002bf..ea7ddc2ca6459 100644 --- a/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.ts @@ -18,7 +18,7 @@ export class ChainRetrievalQa implements INodeType { name: 'chainRetrievalQa', icon: 'fa:link', group: ['transform'], - version: 1, + version: [1, 1.1], description: 'Answer questions about retrieved documents', defaults: { name: 'Question and Answer Chain', @@ -63,7 +63,24 @@ export class ChainRetrievalQa implements INodeType { name: 'query', type: 'string', required: true, - default: '={{ $json.chat_input ?? $json.input }}', + default: '={{ $json.input }}', + displayOptions: { + show: { + '@version': [1], + }, + }, + }, + { + displayName: 'Query', + name: 'query', + type: 'string', + required: true, + default: '={{ $json.chat_input }}', + displayOptions: { + show: { + '@version': [1.1], + }, + }, }, ], }; From 05acd31c1f3491f561dc3678a852f050a2ddaa4b Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Mon, 27 Nov 2023 13:32:49 +0200 Subject: [PATCH 11/16] :zap: error fixes and mapping --- .../VectorStorePinecone.node.ts | 11 +++++++- .../VectorStoreSupabase.node.ts | 25 ++++++++++++++----- .../VectorStoreZep/VectorStoreZep.node.ts | 16 +++++++++--- .../shared/createVectorStoreNode.ts | 6 ++++- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts index 6d2fe912dd69e..a348ffbc40eb8 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.ts @@ -1,4 +1,4 @@ -import type { INodeProperties } from 'n8n-workflow'; +import { NodeOperationError, type INodeProperties } from 'n8n-workflow'; import type { PineconeLibArgs } from 'langchain/vectorstores/pinecone'; import { PineconeStore } from 'langchain/vectorstores/pinecone'; import { Pinecone } from '@pinecone-database/pinecone'; @@ -114,6 +114,15 @@ export const VectorStorePinecone = createVectorStoreNode({ environment: credentials.environment as string, }); + const indexes = (await client.listIndexes()).map((i) => i.name); + + if (!indexes.includes(index)) { + throw new NodeOperationError(context.getNode(), `Index ${index} not found`, { + itemIndex, + description: 'Please check that the index exists in your vector store', + }); + } + const pineconeIndex = client.Index(index); if (options.pineconeNamespace && options.clearNamespace) { diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts index c26128e564dff..5574bbcf8db7b 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreSupabase/VectorStoreSupabase.node.ts @@ -1,4 +1,4 @@ -import type { INodeProperties } from 'n8n-workflow'; +import { NodeOperationError, type INodeProperties } from 'n8n-workflow'; import { createClient } from '@supabase/supabase-js'; import { SupabaseVectorStore } from 'langchain/vectorstores/supabase'; import { createVectorStoreNode } from '../shared/createVectorStoreNode'; @@ -93,10 +93,23 @@ export const VectorStoreSupabase = createVectorStoreNode({ const credentials = await context.getCredentials('supabaseApi'); const client = createClient(credentials.host as string, credentials.serviceRole as string); - void SupabaseVectorStore.fromDocuments(documents, embeddings, { - client, - tableName, - queryName: options.queryName ?? 'match_documents', - }); + try { + await SupabaseVectorStore.fromDocuments(documents, embeddings, { + client, + tableName, + queryName: options.queryName ?? 'match_documents', + }); + } catch (error) { + if (error.message === 'Error inserting: undefined 404 Not Found') { + throw new NodeOperationError(context.getNode(), `Table ${tableName} not found`, { + itemIndex, + description: 'Please check that the table exists in your vector store', + }); + } else { + throw new NodeOperationError(context.getNode(), error, { + itemIndex, + }); + } + } }, }); diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreZep/VectorStoreZep.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreZep/VectorStoreZep.node.ts index 6f9bdbd4d2a10..11937b24e1e7e 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreZep/VectorStoreZep.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreZep/VectorStoreZep.node.ts @@ -1,7 +1,6 @@ -import type { INodeProperties } from 'n8n-workflow'; +import { NodeOperationError, type INodeProperties } from 'n8n-workflow'; import type { IZepConfig } from 'langchain/vectorstores/zep'; import { ZepVectorStore } from 'langchain/vectorstores/zep'; -import type { VectorStore } from 'langchain/vectorstores/base'; import { createVectorStoreNode } from '../shared/createVectorStoreNode'; import { metadataFilterField } from '../../../utils/sharedFields'; @@ -115,6 +114,17 @@ export const VectorStoreZep = createVectorStoreNode({ isAutoEmbedded: options.isAutoEmbedded ?? true, }; - ZepVectorStore.fromDocuments(documents, embeddings, zepConfig) as Promise; + try { + await ZepVectorStore.fromDocuments(documents, embeddings, zepConfig); + } catch (error) { + if (error.message === 'Got an unexpected status code: 400') { + throw new NodeOperationError(context.getNode(), `Collection ${collectionName} not found`, { + itemIndex, + description: + 'Please check that the collection exists in your vector store, or make sure that collection name satixfies naming rules', + }); + } + throw new NodeOperationError(context.getNode(), error, { itemIndex }); + } }, }); 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 32a71541c4354..1bc49c868f319 100644 --- a/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts +++ b/packages/@n8n/nodes-langchain/nodes/vector_store/shared/createVectorStoreNode.ts @@ -260,7 +260,11 @@ export const createVectorStoreNode = (args: VectorStoreNodeConstructorArgs) => ); resultData.push(...serializedDocuments); - await args.populateVectorStore(this, embeddings, processedDocuments, itemIndex); + try { + await args.populateVectorStore(this, embeddings, processedDocuments, itemIndex); + } catch (error) { + throw error; + } } return this.prepareOutputData(resultData); From 06c324478a7008d277e09072a134b44e9768e132 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Mon, 27 Nov 2023 15:57:08 +0200 Subject: [PATCH 12/16] :zap: editor-ui tests fix --- packages/editor-ui/src/__tests__/router.test.ts | 2 +- .../editor-ui/src/components/NDVFloatingNodes.vue | 3 ++- .../src/components/__tests__/NodeDetailsView.test.ts | 12 +++++------- .../src/views/__tests__/VariablesView.spec.ts | 4 +++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/editor-ui/src/__tests__/router.test.ts b/packages/editor-ui/src/__tests__/router.test.ts index 566447fa221d7..beb38e8b17438 100644 --- a/packages/editor-ui/src/__tests__/router.test.ts +++ b/packages/editor-ui/src/__tests__/router.test.ts @@ -3,7 +3,7 @@ import { createComponentRenderer } from '@/__tests__/render'; import router from '@/router'; import { VIEWS } from '@/constants'; import { setupServer } from '@/__tests__/server'; -import { useSettingsStore } from '@/stores'; +import { useSettingsStore } from '@/stores/settings.store'; const App = { template: '
', diff --git a/packages/editor-ui/src/components/NDVFloatingNodes.vue b/packages/editor-ui/src/components/NDVFloatingNodes.vue index c620997342422..79ac9059d6559 100644 --- a/packages/editor-ui/src/components/NDVFloatingNodes.vue +++ b/packages/editor-ui/src/components/NDVFloatingNodes.vue @@ -38,7 +38,8 @@