From 76ac97fa5051d33fe6e302aa72936831bbb04b63 Mon Sep 17 00:00:00 2001 From: paulpaliychuk Date: Mon, 19 Feb 2024 22:11:07 -0500 Subject: [PATCH 01/12] wip --- .../memory/ZepMemoryCloud/ZepMemoryCloud.ts | 172 +++++++++++++ .../nodes/memory/ZepMemoryCloud/zep.svg | 19 ++ .../nodes/vectorstores/ZepCloud/ZepCloud.ts | 234 ++++++++++++++++++ .../nodes/vectorstores/ZepCloud/zep.svg | 19 ++ packages/components/package.json | 1 + 5 files changed, 445 insertions(+) create mode 100644 packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts create mode 100644 packages/components/nodes/memory/ZepMemoryCloud/zep.svg create mode 100644 packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts create mode 100644 packages/components/nodes/vectorstores/ZepCloud/zep.svg diff --git a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts new file mode 100644 index 00000000..336fbc4d --- /dev/null +++ b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts @@ -0,0 +1,172 @@ +import { IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' +import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { ZepMemory, ZepMemoryInput } from '@getzep/zep-cloud/langchain' + +import { ICommonObject } from '../../../src' +import { InputValues, MemoryVariables, OutputValues } from 'langchain/memory' +import { BaseMessage } from 'langchain/schema' + +class ZepMemoryCloud_Memory implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'Zep Memory - Cloud' + this.name = 'ZepMemory (Cloud)' + this.version = 2.0 + this.type = 'ZepMemory' + this.icon = 'zep.svg' + this.category = 'Memory' + this.description = 'Summarizes the conversation and stores the memory in zep server' + this.baseClasses = [this.type, ...getBaseClasses(ZepMemory)] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + description: 'Configure JWT authentication on your Zep instance (Optional)', + credentialNames: ['zepMemoryApi'] + } + this.inputs = [ + { + label: 'Session Id', + name: 'sessionId', + type: 'string', + description: + 'If not specified, a random id will be used. Learn more', + default: '', + additionalParams: true, + optional: true + }, + { + label: 'Memory Type', + name: 'memoryType', + type: 'string', + default: 'perpetual', + description: 'Zep Memory Type, can be perpetual or message_window', + additionalParams: true + }, + { + label: 'AI Prefix', + name: 'aiPrefix', + type: 'string', + default: 'ai', + additionalParams: true + }, + { + label: 'Human Prefix', + name: 'humanPrefix', + type: 'string', + default: 'human', + additionalParams: true + }, + { + label: 'Memory Key', + name: 'memoryKey', + type: 'string', + default: 'chat_history', + additionalParams: true + }, + { + label: 'Output Key', + name: 'outputKey', + type: 'string', + default: 'text', + additionalParams: true + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + return await initalizeZep(nodeData, options) + } +} + +const initalizeZep = async (nodeData: INodeData, options: ICommonObject): Promise => { + const aiPrefix = nodeData.inputs?.aiPrefix as string + const humanPrefix = nodeData.inputs?.humanPrefix as string + const memoryKey = nodeData.inputs?.memoryKey as string + const memoryType = nodeData.inputs?.memoryType as 'perpetual' | 'message_window' + const sessionId = nodeData.inputs?.sessionId as string + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const apiKey = getCredentialParam('apiKey', credentialData, nodeData) + + const obj: ZepMemoryInput & ZepMemoryExtendedInput = { + apiKey, + baseURL: 'https://api.development.getzep.com', + aiPrefix, + humanPrefix, + memoryKey, + sessionId, + memoryType: memoryType + } + + return new ZepMemoryExtended(obj) +} + +interface ZepMemoryExtendedInput { + memoryType?: 'perpetual' | 'message_window' +} + +class ZepMemoryExtended extends ZepMemory implements MemoryMethods { + memoryType: 'perpetual' | 'message_window' + + constructor(fields: ZepMemoryInput & ZepMemoryExtendedInput) { + super(fields) + this.memoryType = fields.memoryType ?? 'perpetual' + } + + async loadMemoryVariables(values: InputValues, overrideSessionId = ''): Promise { + if (overrideSessionId) { + this.sessionId = overrideSessionId + } + return super.loadMemoryVariables({ ...values, memoryType: this.memoryType }) + } + + async saveContext(inputValues: InputValues, outputValues: OutputValues, overrideSessionId = ''): Promise { + if (overrideSessionId) { + this.sessionId = overrideSessionId + } + return super.saveContext(inputValues, outputValues) + } + + async clear(overrideSessionId = ''): Promise { + if (overrideSessionId) { + this.sessionId = overrideSessionId + } + return super.clear() + } + + async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + const id = overrideSessionId ? overrideSessionId : this.sessionId + const memoryVariables = await this.loadMemoryVariables({}, id) + const baseMessages = memoryVariables[this.memoryKey] + return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) + } + + async addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId = ''): Promise { + const id = overrideSessionId ? overrideSessionId : this.sessionId + const input = msgArray.find((msg) => msg.type === 'userMessage') + const output = msgArray.find((msg) => msg.type === 'apiMessage') + const inputValues = { ['input']: input?.text } + const outputValues = { output: output?.text } + + await this.saveContext(inputValues, outputValues, id) + } + + async clearChatMessages(overrideSessionId = ''): Promise { + const id = overrideSessionId ? overrideSessionId : this.sessionId + await this.clear(id) + } +} + +module.exports = { nodeClass: ZepMemoryCloud_Memory } diff --git a/packages/components/nodes/memory/ZepMemoryCloud/zep.svg b/packages/components/nodes/memory/ZepMemoryCloud/zep.svg new file mode 100644 index 00000000..6cbbaad2 --- /dev/null +++ b/packages/components/nodes/memory/ZepMemoryCloud/zep.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts new file mode 100644 index 00000000..10847bb8 --- /dev/null +++ b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts @@ -0,0 +1,234 @@ +import { flatten } from 'lodash' +import { IDocument, ZepClient } from '@getzep/zep-cloud' +import { IZepConfig, ZepVectorStore } from '@getzep/zep-cloud/langchain' +import { Embeddings } from 'langchain/embeddings/base' +import { Document } from 'langchain/document' +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' +import { FakeEmbeddings } from 'langchain/embeddings/fake' +class Zep_CloudVectorStores implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + badge: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Zep Collection - Cloud' + this.name = 'zepCloud' + this.version = 2.0 + this.type = 'Zep' + this.icon = 'zep.svg' + this.category = 'Vector Stores' + this.description = + 'Upsert embedded data and perform similarity or mmr search upon query using Zep, a fast and scalable building block for LLM apps' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.badge = 'NEW' + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: false, + description: 'Configure JWT authentication on your Zep instance (Optional)', + credentialNames: ['zepMemoryApi'] + } + this.inputs = [ + { + label: 'Document', + name: 'document', + type: 'Document', + list: true, + optional: true + }, + { + label: 'Zep Collection', + name: 'zepCollection', + type: 'string', + placeholder: 'my-first-collection' + }, + { + label: 'Zep Metadata Filter', + name: 'zepMetadataFilter', + type: 'json', + optional: true, + additionalParams: true + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to 4', + placeholder: '4', + type: 'number', + additionalParams: true, + optional: true + } + ] + addMMRInputParams(this.inputs) + this.outputs = [ + { + label: 'Zep Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Zep Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(ZepVectorStore)] + } + ] + } + + //@ts-ignore + vectorStoreMethods = { + async upsert(nodeData: INodeData, options: ICommonObject): Promise { + const zepCollection = nodeData.inputs?.zepCollection as string + const docs = nodeData.inputs?.document as Document[] + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const apiKey = getCredentialParam('apiKey', credentialData, nodeData) + const flattenDocs = docs && docs.length ? flatten(docs) : [] + const finalDocs = [] + for (let i = 0; i < flattenDocs.length; i += 1) { + if (flattenDocs[i] && flattenDocs[i].pageContent) { + finalDocs.push(new Document(flattenDocs[i])) + } + } + const client = await ZepClient.init(apiKey, 'https://api.development.getzep.com') + const zepConfig = { + apiKey: apiKey, + collectionName: zepCollection, + client + } + try { + await ZepVectorStore.fromDocuments(finalDocs, new FakeEmbeddings(), zepConfig) + } catch (e) { + throw new Error(e) + } + } + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const zepCollection = nodeData.inputs?.zepCollection as string + const zepMetadataFilter = nodeData.inputs?.zepMetadataFilter + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const apiKey = getCredentialParam('apiKey', credentialData, nodeData) + + const zepConfig: IZepConfig & Partial = { + apiUrl: 'https://api.development.getzep.com', + apiKey, + collectionName: zepCollection + } + if (zepMetadataFilter) { + zepConfig.filter = typeof zepMetadataFilter === 'object' ? zepMetadataFilter : JSON.parse(zepMetadataFilter) + } + const client = await ZepClient.init(zepConfig.apiKey, zepConfig.apiUrl) + zepConfig.client = client + const vectorStore = await ZepExistingVS.init(zepConfig) + return resolveVectorStoreOrRetriever(nodeData, vectorStore) + } +} + +interface ZepFilter { + filter: Record +} + +function zepDocsToDocumentsAndScore(results: IDocument[]): [Document, number][] { + return results.map((d) => [ + new Document({ + pageContent: d.content, + metadata: d.metadata + }), + d.score ? d.score : 0 + ]) +} + +function assignMetadata(value: string | Record | object | undefined): Record | undefined { + if (typeof value === 'object' && value !== null) { + return value as Record + } + if (value !== undefined) { + console.warn('Metadata filters must be an object, Record, or undefined.') + } + return undefined +} + +class ZepExistingVS extends ZepVectorStore { + filter?: Record + args?: IZepConfig & Partial + + constructor(embeddings: Embeddings, args: IZepConfig & Partial) { + super(embeddings, args) + this.filter = args.filter + this.args = args + } + + async initializeCollection(args: IZepConfig & Partial) { + this.client = await ZepClient.init(args.apiKey, args.apiUrl) + try { + this.collection = await this.client.document.getCollection(args.collectionName) + } catch (err) { + if (err instanceof Error) { + if (err.name === 'NotFoundError') { + await this.createNewCollection(args) + } else { + throw err + } + } + } + } + + async createNewCollection(args: IZepConfig & Partial) { + this.collection = await this.client.document.addCollection({ + name: args.collectionName, + description: args.description, + metadata: args.metadata + }) + } + + async similaritySearchVectorWithScore( + query: number[], + k: number, + filter?: Record | undefined + ): Promise<[Document, number][]> { + if (filter && this.filter) { + throw new Error('cannot provide both `filter` and `this.filter`') + } + const _filters = filter ?? this.filter + const ANDFilters = [] + for (const filterKey in _filters) { + let filterVal = _filters[filterKey] + if (typeof filterVal === 'string') filterVal = `"${filterVal}"` + ANDFilters.push({ jsonpath: `$[*] ? (@.${filterKey} == ${filterVal})` }) + } + const newfilter = { + where: { and: ANDFilters } + } + await this.initializeCollection(this.args!).catch((err) => { + console.error('Error initializing collection:', err) + throw err + }) + const results = await this.collection.search( + { + embedding: new Float32Array(query), + metadata: assignMetadata(newfilter) + }, + k + ) + return zepDocsToDocumentsAndScore(results) + } + + static async fromExistingIndex(embeddings: Embeddings, dbConfig: IZepConfig & Partial): Promise { + console.log('fromExistingIndex') + const instance = new this(embeddings, dbConfig) + return instance + } +} + +module.exports = { nodeClass: Zep_CloudVectorStores } diff --git a/packages/components/nodes/vectorstores/ZepCloud/zep.svg b/packages/components/nodes/vectorstores/ZepCloud/zep.svg new file mode 100644 index 00000000..6cbbaad2 --- /dev/null +++ b/packages/components/nodes/vectorstores/ZepCloud/zep.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/packages/components/package.json b/packages/components/package.json index b53945bd..0f1c70a8 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -23,6 +23,7 @@ "@dqbd/tiktoken": "^1.0.7", "@elastic/elasticsearch": "^8.9.0", "@getzep/zep-js": "^0.9.0", + "@getzep/zep-cloud": "file:/Users/paulpaliychuk/job/zep-js/getzep-zep-js-v2.0.0-rc.37.tgz", "@gomomento/sdk": "^1.51.1", "@gomomento/sdk-core": "^1.51.1", "@google-ai/generativelanguage": "^0.2.1", From 29c86f77bf9a94d52ebc4622572f710c3e72a288 Mon Sep 17 00:00:00 2001 From: paulpaliychuk Date: Mon, 19 Feb 2024 22:58:28 -0500 Subject: [PATCH 02/12] feat: Update @qdrant/openapi-typescript-fetch resolution --- package.json | 3 +++ packages/components/package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5f5f5812..a296ed6c 100644 --- a/package.json +++ b/package.json @@ -53,5 +53,8 @@ }, "engines": { "node": ">=18.15.0" + }, + "resolutions": { + "@qdrant/openapi-typescript-fetch": "1.2.1" } } diff --git a/packages/components/package.json b/packages/components/package.json index 0f1c70a8..eb72c784 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -22,8 +22,8 @@ "@datastax/astra-db-ts": "^0.1.2", "@dqbd/tiktoken": "^1.0.7", "@elastic/elasticsearch": "^8.9.0", + "@getzep/zep-cloud": "npm:@getzep/zep-js@next", "@getzep/zep-js": "^0.9.0", - "@getzep/zep-cloud": "file:/Users/paulpaliychuk/job/zep-js/getzep-zep-js-v2.0.0-rc.37.tgz", "@gomomento/sdk": "^1.51.1", "@gomomento/sdk-core": "^1.51.1", "@google-ai/generativelanguage": "^0.2.1", From 9da7a1b4de3b3e57c680db70f4469d72cbcb6cbd Mon Sep 17 00:00:00 2001 From: paulpaliychuk Date: Tue, 20 Feb 2024 00:31:35 -0500 Subject: [PATCH 03/12] feat: Finalize zep-cloud integration, update naming --- .../nodes/memory/ZepMemory/ZepMemory.ts | 8 +++---- .../memory/ZepMemoryCloud/ZepMemoryCloud.ts | 22 ++++++++++++++----- .../components/nodes/vectorstores/Zep/Zep.ts | 4 ++-- .../nodes/vectorstores/Zep/Zep_Existing.ts | 4 ++-- .../nodes/vectorstores/Zep/Zep_Upsert.ts | 4 ++-- .../nodes/vectorstores/ZepCloud/ZepCloud.ts | 2 +- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts index d511e7b2..2715706c 100644 --- a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts +++ b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts @@ -17,8 +17,8 @@ class ZepMemory_Memory implements INode { inputs: INodeParams[] constructor() { - this.label = 'Zep Memory' - this.name = 'ZepMemory' + this.label = 'Zep Memory - Open Source' + this.name = 'Zep Memory (Open Source)' this.version = 2.0 this.type = 'ZepMemory' this.icon = 'zep.svg' @@ -97,11 +97,11 @@ class ZepMemory_Memory implements INode { } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - return await initalizeZep(nodeData, options) + return await initializeZep(nodeData, options) } } -const initalizeZep = async (nodeData: INodeData, options: ICommonObject): Promise => { +const initializeZep = async (nodeData: INodeData, options: ICommonObject): Promise => { const baseURL = nodeData.inputs?.baseURL as string const aiPrefix = nodeData.inputs?.aiPrefix as string const humanPrefix = nodeData.inputs?.humanPrefix as string diff --git a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts index 336fbc4d..f5926d87 100644 --- a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts +++ b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts @@ -20,7 +20,7 @@ class ZepMemoryCloud_Memory implements INode { constructor() { this.label = 'Zep Memory - Cloud' - this.name = 'ZepMemory (Cloud)' + this.name = 'Zep Memory (Cloud)' this.version = 2.0 this.type = 'ZepMemory' this.icon = 'zep.svg' @@ -75,6 +75,13 @@ class ZepMemoryCloud_Memory implements INode { default: 'chat_history', additionalParams: true }, + { + label: 'Input Key', + name: 'inputKey', + type: 'string', + default: 'input', + additionalParams: true + }, { label: 'Output Key', name: 'outputKey', @@ -86,20 +93,21 @@ class ZepMemoryCloud_Memory implements INode { } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - return await initalizeZep(nodeData, options) + return await initializeZep(nodeData, options) } } -const initalizeZep = async (nodeData: INodeData, options: ICommonObject): Promise => { +const initializeZep = async (nodeData: INodeData, options: ICommonObject): Promise => { const aiPrefix = nodeData.inputs?.aiPrefix as string const humanPrefix = nodeData.inputs?.humanPrefix as string const memoryKey = nodeData.inputs?.memoryKey as string + const inputKey = nodeData.inputs?.inputKey as string + const memoryType = nodeData.inputs?.memoryType as 'perpetual' | 'message_window' const sessionId = nodeData.inputs?.sessionId as string const credentialData = await getCredentialData(nodeData.credential ?? '', options) const apiKey = getCredentialParam('apiKey', credentialData, nodeData) - const obj: ZepMemoryInput & ZepMemoryExtendedInput = { apiKey, baseURL: 'https://api.development.getzep.com', @@ -107,7 +115,9 @@ const initalizeZep = async (nodeData: INodeData, options: ICommonObject): Promis humanPrefix, memoryKey, sessionId, - memoryType: memoryType + inputKey, + memoryType: memoryType, + returnMessages: true } return new ZepMemoryExtended(obj) @@ -157,7 +167,7 @@ class ZepMemoryExtended extends ZepMemory implements MemoryMethods { const id = overrideSessionId ? overrideSessionId : this.sessionId const input = msgArray.find((msg) => msg.type === 'userMessage') const output = msgArray.find((msg) => msg.type === 'apiMessage') - const inputValues = { ['input']: input?.text } + const inputValues = { [this.inputKey ?? 'input']: input?.text } const outputValues = { output: output?.text } await this.saveContext(inputValues, outputValues, id) diff --git a/packages/components/nodes/vectorstores/Zep/Zep.ts b/packages/components/nodes/vectorstores/Zep/Zep.ts index c5a8f0d4..7bd7a08c 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep.ts @@ -22,8 +22,8 @@ class Zep_VectorStores implements INode { outputs: INodeOutputsValue[] constructor() { - this.label = 'Zep' - this.name = 'zep' + this.label = 'Zep Collection - Open Source' + this.name = 'Zep Collection (Open Source)' this.version = 2.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts index 75c2bd3f..a8c57236 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts @@ -20,8 +20,8 @@ class Zep_Existing_VectorStores implements INode { outputs: INodeOutputsValue[] constructor() { - this.label = 'Zep Load Existing Index' - this.name = 'zepExistingIndex' + this.label = 'Zep Load Existing Index (Open Source)' + this.name = 'Zep Existing Index (Open Source)' this.version = 1.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts index f05fc207..83dcf710 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts @@ -20,8 +20,8 @@ class Zep_Upsert_VectorStores implements INode { outputs: INodeOutputsValue[] constructor() { - this.label = 'Zep Upsert Document' - this.name = 'zepUpsert' + this.label = 'Zep Upsert Document (Open Source)' + this.name = 'Zep Upsert (Open Source)' this.version = 1.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts index 10847bb8..74f143ed 100644 --- a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts +++ b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts @@ -23,7 +23,7 @@ class Zep_CloudVectorStores implements INode { constructor() { this.label = 'Zep Collection - Cloud' - this.name = 'zepCloud' + this.name = 'Zep Collection Cloud' this.version = 2.0 this.type = 'Zep' this.icon = 'zep.svg' From aec0645fba39eb48ed7dc2fc99b4c28911c7ecaa Mon Sep 17 00:00:00 2001 From: paulpaliychuk Date: Tue, 20 Feb 2024 00:45:35 -0500 Subject: [PATCH 04/12] chore: Update labels + get rid of dev urls --- packages/components/nodes/memory/ZepMemory/ZepMemory.ts | 2 +- .../components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts | 3 +-- packages/components/nodes/vectorstores/Zep/Zep.ts | 2 +- packages/components/nodes/vectorstores/Zep/Zep_Existing.ts | 4 ++-- packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts | 4 ++-- packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts | 3 +-- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts index 2715706c..956630f4 100644 --- a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts +++ b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts @@ -18,7 +18,7 @@ class ZepMemory_Memory implements INode { constructor() { this.label = 'Zep Memory - Open Source' - this.name = 'Zep Memory (Open Source)' + this.name = 'Zep Memory - Open Source' this.version = 2.0 this.type = 'ZepMemory' this.icon = 'zep.svg' diff --git a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts index f5926d87..ef1497dc 100644 --- a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts +++ b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts @@ -20,7 +20,7 @@ class ZepMemoryCloud_Memory implements INode { constructor() { this.label = 'Zep Memory - Cloud' - this.name = 'Zep Memory (Cloud)' + this.name = 'Zep Memory - Cloud' this.version = 2.0 this.type = 'ZepMemory' this.icon = 'zep.svg' @@ -110,7 +110,6 @@ const initializeZep = async (nodeData: INodeData, options: ICommonObject): Promi const apiKey = getCredentialParam('apiKey', credentialData, nodeData) const obj: ZepMemoryInput & ZepMemoryExtendedInput = { apiKey, - baseURL: 'https://api.development.getzep.com', aiPrefix, humanPrefix, memoryKey, diff --git a/packages/components/nodes/vectorstores/Zep/Zep.ts b/packages/components/nodes/vectorstores/Zep/Zep.ts index 7bd7a08c..f27cc52e 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep.ts @@ -23,7 +23,7 @@ class Zep_VectorStores implements INode { constructor() { this.label = 'Zep Collection - Open Source' - this.name = 'Zep Collection (Open Source)' + this.name = 'Zep Collection - Open Source' this.version = 2.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts index a8c57236..26cb5cb2 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts @@ -20,8 +20,8 @@ class Zep_Existing_VectorStores implements INode { outputs: INodeOutputsValue[] constructor() { - this.label = 'Zep Load Existing Index (Open Source)' - this.name = 'Zep Existing Index (Open Source)' + this.label = 'Zep Load Existing Index - Open Source' + this.name = 'Zep Existing Index - Open Source' this.version = 1.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts index 83dcf710..5b23db41 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts @@ -20,8 +20,8 @@ class Zep_Upsert_VectorStores implements INode { outputs: INodeOutputsValue[] constructor() { - this.label = 'Zep Upsert Document (Open Source)' - this.name = 'Zep Upsert (Open Source)' + this.label = 'Zep Upsert Document - Open Source' + this.name = 'Zep Upsert - Open Source' this.version = 1.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts index 74f143ed..58087d5b 100644 --- a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts +++ b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts @@ -23,7 +23,7 @@ class Zep_CloudVectorStores implements INode { constructor() { this.label = 'Zep Collection - Cloud' - this.name = 'Zep Collection Cloud' + this.name = 'Zep Collection - Cloud' this.version = 2.0 this.type = 'Zep' this.icon = 'zep.svg' @@ -121,7 +121,6 @@ class Zep_CloudVectorStores implements INode { const apiKey = getCredentialParam('apiKey', credentialData, nodeData) const zepConfig: IZepConfig & Partial = { - apiUrl: 'https://api.development.getzep.com', apiKey, collectionName: zepCollection } From 23f7e7802f6a28092ee5f9361f70c30870b5f888 Mon Sep 17 00:00:00 2001 From: Jaredude Date: Wed, 21 Feb 2024 21:19:38 -0600 Subject: [PATCH 05/12] handles scenario where NodesPool require call fails Currently, the following file results in an error: Flowise/packages/components/dist/nodes/documentloaders/Subtitles/Subtitles.js:3:15 The result is that initializeNodes fails on all nodes, and all other code in initDatabase fails to load --- packages/server/src/NodesPool.ts | 51 ++++++++++++++++++-------------- packages/server/src/index.ts | 3 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/packages/server/src/NodesPool.ts b/packages/server/src/NodesPool.ts index f4681d4a..86736d45 100644 --- a/packages/server/src/NodesPool.ts +++ b/packages/server/src/NodesPool.ts @@ -4,6 +4,7 @@ import { Dirent } from 'fs' import { getNodeModulesPackagePath } from './utils' import { promises } from 'fs' import { ICommonObject } from 'flowise-components' +import logger from './utils/logger' export class NodesPool { componentNodes: IComponentNodes = {} @@ -28,36 +29,40 @@ export class NodesPool { return Promise.all( nodeFiles.map(async (file) => { if (file.endsWith('.js')) { - const nodeModule = await require(file) + try { + const nodeModule = await require(file) - if (nodeModule.nodeClass) { - const newNodeInstance = new nodeModule.nodeClass() - newNodeInstance.filePath = file + if (nodeModule.nodeClass) { + const newNodeInstance = new nodeModule.nodeClass() + newNodeInstance.filePath = file - // Replace file icon with absolute path - if ( - newNodeInstance.icon && - (newNodeInstance.icon.endsWith('.svg') || - newNodeInstance.icon.endsWith('.png') || - newNodeInstance.icon.endsWith('.jpg')) - ) { - const filePath = file.replace(/\\/g, '/').split('/') - filePath.pop() - const nodeIconAbsolutePath = `${filePath.join('/')}/${newNodeInstance.icon}` - newNodeInstance.icon = nodeIconAbsolutePath + // Replace file icon with absolute path + if ( + newNodeInstance.icon && + (newNodeInstance.icon.endsWith('.svg') || + newNodeInstance.icon.endsWith('.png') || + newNodeInstance.icon.endsWith('.jpg')) + ) { + const filePath = file.replace(/\\/g, '/').split('/') + filePath.pop() + const nodeIconAbsolutePath = `${filePath.join('/')}/${newNodeInstance.icon}` + newNodeInstance.icon = nodeIconAbsolutePath - // Store icon path for componentCredentials - if (newNodeInstance.credential) { - for (const credName of newNodeInstance.credential.credentialNames) { - this.credentialIconPath[credName] = nodeIconAbsolutePath + // Store icon path for componentCredentials + if (newNodeInstance.credential) { + for (const credName of newNodeInstance.credential.credentialNames) { + this.credentialIconPath[credName] = nodeIconAbsolutePath + } } } - } - const skipCategories = ['Analytic'] - if (!skipCategories.includes(newNodeInstance.category)) { - this.componentNodes[newNodeInstance.name] = newNodeInstance + const skipCategories = ['Analytic'] + if (!skipCategories.includes(newNodeInstance.category)) { + this.componentNodes[newNodeInstance.name] = newNodeInstance + } } + } catch (err) { + logger.error(`❌ [server]: Error during initDatabase with file ${file}:`, err) } } }) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 20102a42..aef8494a 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -85,7 +85,7 @@ export class App { // Initialize database this.AppDataSource.initialize() .then(async () => { - logger.info('📦 [server]: Data Source has been initialized!') + logger.info('📦 [server]: Data Source is being initialized!') // Run Migrations Scripts await this.AppDataSource.runMigrations({ transaction: 'each' }) @@ -112,6 +112,7 @@ export class App { // Initialize telemetry this.telemetry = new Telemetry() + logger.info('📦 [server]: Data Source has been initialized!') }) .catch((err) => { logger.error('❌ [server]: Error during Data Source initialization:', err) From 2f4134a2915d69712775e0c32af8f756dc79e325 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 22 Feb 2024 23:09:58 +0800 Subject: [PATCH 06/12] upstash singleton --- .../UpstashRedisBackedChatMemory.ts | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 0f26fa33..52da0f37 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -1,4 +1,5 @@ -import { Redis } from '@upstash/redis' +import { Redis, RedisConfigNodejs } from '@upstash/redis' +import { isEqual } from 'lodash' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' import { UpstashRedisChatMessageHistory } from '@langchain/community/stores/message/upstash_redis' import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, StoredMessage, BaseMessage } from '@langchain/core/messages' @@ -6,6 +7,24 @@ import { FlowiseMemory, IMessage, INode, INodeData, INodeParams, MemoryMethods, import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ICommonObject } from '../../../src/Interface' +let redisClientSingleton: Redis +let redisClientOption: RedisConfigNodejs + +const getRedisClientbyOption = (option: RedisConfigNodejs) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } else if (redisClientSingleton && !isEqual(option, redisClientOption)) { + // if client exists but option changed + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } + return redisClientSingleton +} + class UpstashRedisBackedChatMemory_Memory implements INode { label: string name: string @@ -75,7 +94,7 @@ const initalizeUpstashRedis = async (nodeData: INodeData, options: ICommonObject const credentialData = await getCredentialData(nodeData.credential ?? '', options) const upstashRestToken = getCredentialParam('upstashRestToken', credentialData, nodeData) - const client = new Redis({ + const client = getRedisClientbyOption({ url: baseURL, token: upstashRestToken }) From 77281782535d542364c6c737bfb19db60f12a2d1 Mon Sep 17 00:00:00 2001 From: paulpaliychuk Date: Thu, 22 Feb 2024 09:43:57 -0800 Subject: [PATCH 07/12] fix: Linter errors --- packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts index 58087d5b..fdbae703 100644 --- a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts +++ b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts @@ -224,9 +224,7 @@ class ZepExistingVS extends ZepVectorStore { } static async fromExistingIndex(embeddings: Embeddings, dbConfig: IZepConfig & Partial): Promise { - console.log('fromExistingIndex') - const instance = new this(embeddings, dbConfig) - return instance + return new this(embeddings, dbConfig) } } From 0a5195d1abbaf563c6de1a5f0cb95a13b164c3ed Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 23 Feb 2024 07:07:46 +0530 Subject: [PATCH 08/12] Bugfix: View Toggle loses state when button is clicked twice. --- packages/ui/src/views/chatflows/index.js | 2 ++ packages/ui/src/views/marketplaces/index.js | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index c87ad306..c1e9ade4 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -47,6 +47,8 @@ const Chatflows = () => { const [view, setView] = React.useState(localStorage.getItem('flowDisplayStyle') || 'card') const handleChange = (event, nextView) => { + if (nextView === null) return + console.log('nextView == ' + nextView) localStorage.setItem('flowDisplayStyle', nextView) setView(nextView) } diff --git a/packages/ui/src/views/marketplaces/index.js b/packages/ui/src/views/marketplaces/index.js index e5a65cb9..a6d29e43 100644 --- a/packages/ui/src/views/marketplaces/index.js +++ b/packages/ui/src/views/marketplaces/index.js @@ -131,6 +131,7 @@ const Marketplace = () => { } const handleViewChange = (event, nextView) => { + if (nextView === null) return localStorage.setItem('mpDisplayStyle', nextView) setView(nextView) } From f690943316f175f80f9ee0fdf602ba27c64e3c1b Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 23 Feb 2024 07:19:26 +0530 Subject: [PATCH 09/12] Bugfix: lint fixes (no-console) --- packages/ui/src/views/chatflows/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index c1e9ade4..6426cdd6 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -48,7 +48,6 @@ const Chatflows = () => { const handleChange = (event, nextView) => { if (nextView === null) return - console.log('nextView == ' + nextView) localStorage.setItem('flowDisplayStyle', nextView) setView(nextView) } From 46c32693ad1059747041f31c9999923d06a1337e Mon Sep 17 00:00:00 2001 From: Henry Date: Sat, 24 Feb 2024 02:25:07 +0800 Subject: [PATCH 10/12] update langsmith version --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index b0d40ff7..1a2b060c 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -64,7 +64,7 @@ "langchain": "^0.1.20", "langfuse": "3.1.0", "langfuse-langchain": "^3.1.0", - "langsmith": "0.0.63", + "langsmith": "0.1.6", "linkifyjs": "^4.1.1", "llamaindex": "^0.0.48", "lunary": "^0.6.16", From 6819d5f66ba58c4d2a99f34c28bd3f39e8a982fb Mon Sep 17 00:00:00 2001 From: paulpaliychuk Date: Sat, 24 Feb 2024 13:47:53 -0500 Subject: [PATCH 11/12] chore: Revert node names changes + update new node names to correct format --- packages/components/nodes/memory/ZepMemory/ZepMemory.ts | 2 +- .../nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts | 2 +- packages/components/nodes/vectorstores/Zep/Zep.ts | 2 +- .../components/nodes/vectorstores/Zep/Zep_Existing.ts | 2 +- packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts | 2 +- .../components/nodes/vectorstores/ZepCloud/ZepCloud.ts | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts index 956630f4..c8d3d155 100644 --- a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts +++ b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts @@ -18,7 +18,7 @@ class ZepMemory_Memory implements INode { constructor() { this.label = 'Zep Memory - Open Source' - this.name = 'Zep Memory - Open Source' + this.name = 'ZepMemory' this.version = 2.0 this.type = 'ZepMemory' this.icon = 'zep.svg' diff --git a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts index ef1497dc..d5c950f4 100644 --- a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts +++ b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts @@ -20,7 +20,7 @@ class ZepMemoryCloud_Memory implements INode { constructor() { this.label = 'Zep Memory - Cloud' - this.name = 'Zep Memory - Cloud' + this.name = 'ZepMemoryCloud' this.version = 2.0 this.type = 'ZepMemory' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/Zep/Zep.ts b/packages/components/nodes/vectorstores/Zep/Zep.ts index f27cc52e..c8a78eac 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep.ts @@ -23,7 +23,7 @@ class Zep_VectorStores implements INode { constructor() { this.label = 'Zep Collection - Open Source' - this.name = 'Zep Collection - Open Source' + this.name = 'zep' this.version = 2.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts index 26cb5cb2..58f02797 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts @@ -21,7 +21,7 @@ class Zep_Existing_VectorStores implements INode { constructor() { this.label = 'Zep Load Existing Index - Open Source' - this.name = 'Zep Existing Index - Open Source' + this.name = 'zepExistingIndex' this.version = 1.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts index 5b23db41..b81935d4 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts @@ -21,7 +21,7 @@ class Zep_Upsert_VectorStores implements INode { constructor() { this.label = 'Zep Upsert Document - Open Source' - this.name = 'Zep Upsert - Open Source' + this.name = 'zepUpsert' this.version = 1.0 this.type = 'Zep' this.icon = 'zep.svg' diff --git a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts index fdbae703..49da7c0d 100644 --- a/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts +++ b/packages/components/nodes/vectorstores/ZepCloud/ZepCloud.ts @@ -7,6 +7,7 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' import { FakeEmbeddings } from 'langchain/embeddings/fake' + class Zep_CloudVectorStores implements INode { label: string name: string @@ -23,7 +24,7 @@ class Zep_CloudVectorStores implements INode { constructor() { this.label = 'Zep Collection - Cloud' - this.name = 'Zep Collection - Cloud' + this.name = 'zepCloud' this.version = 2.0 this.type = 'Zep' this.icon = 'zep.svg' @@ -100,7 +101,7 @@ class Zep_CloudVectorStores implements INode { finalDocs.push(new Document(flattenDocs[i])) } } - const client = await ZepClient.init(apiKey, 'https://api.development.getzep.com') + const client = await ZepClient.init(apiKey) const zepConfig = { apiKey: apiKey, collectionName: zepCollection, @@ -127,8 +128,7 @@ class Zep_CloudVectorStores implements INode { if (zepMetadataFilter) { zepConfig.filter = typeof zepMetadataFilter === 'object' ? zepMetadataFilter : JSON.parse(zepMetadataFilter) } - const client = await ZepClient.init(zepConfig.apiKey, zepConfig.apiUrl) - zepConfig.client = client + zepConfig.client = await ZepClient.init(zepConfig.apiKey) const vectorStore = await ZepExistingVS.init(zepConfig) return resolveVectorStoreOrRetriever(nodeData, vectorStore) } From f1c704cfd10c9e18e9d27dcc42836c87aec1f159 Mon Sep 17 00:00:00 2001 From: YISH Date: Mon, 26 Feb 2024 14:01:24 +0800 Subject: [PATCH 12/12] Feature: OverrideConfig allows partial override --- packages/server/src/utils/index.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 4f222151..2903d426 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -629,7 +629,33 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: } } - let paramValue = overrideConfig[config] ?? inputsObj[config] + let paramValue = inputsObj[config] + const overrideConfigValue = overrideConfig[config] + if (overrideConfigValue) { + if (typeof overrideConfigValue === 'object') { + switch (typeof paramValue) { + case 'string': + if (paramValue.startsWith('{') && paramValue.endsWith('}')) { + try { + paramValue = Object.assign({}, JSON.parse(paramValue), overrideConfigValue) + break + } catch (e) { + // ignore + } + } + paramValue = overrideConfigValue + break + case 'object': + paramValue = Object.assign({}, paramValue, overrideConfigValue) + break + default: + paramValue = overrideConfigValue + break + } + } else { + paramValue = overrideConfigValue + } + } // Check if boolean if (paramValue === 'true') paramValue = true else if (paramValue === 'false') paramValue = false