From 50903453f000eb79f1541e5696f6ec6bca7a877a Mon Sep 17 00:00:00 2001 From: BitVoyagerMan Date: Thu, 21 Sep 2023 02:40:55 -0400 Subject: [PATCH 01/55] add bittensor chatmodel --- .../nodes/chatmodels/Bittensor/Bittensor.ts | 48 +++++++++++++++ .../nodes/chatmodels/Bittensor/logo.png | Bin 0 -> 24561 bytes .../nodes/llms/Bittensor/Bittensor.ts | 58 ++++++++++++++++++ .../components/nodes/llms/Bittensor/logo.png | Bin 0 -> 24561 bytes 4 files changed, 106 insertions(+) create mode 100644 packages/components/nodes/chatmodels/Bittensor/Bittensor.ts create mode 100644 packages/components/nodes/chatmodels/Bittensor/logo.png create mode 100644 packages/components/nodes/llms/Bittensor/Bittensor.ts create mode 100644 packages/components/nodes/llms/Bittensor/logo.png diff --git a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts new file mode 100644 index 00000000..8ca05634 --- /dev/null +++ b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts @@ -0,0 +1,48 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import {NIBittensorChatModel, BittensorInput} from 'langchain/experimental/chat_models/bittensor'; + +class Bittensor_ChatModels implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'NIBittensorChat' + this.name = 'NIBittensorChatModel' + this.version = 1.0 + this.type = 'BittensorChat' + this.icon = 'logo.png' + this.category = 'Chat Models' + this.description = 'Wrapper around Bittensor subnet 1 large language models' + this.baseClasses = [this.type, ...getBaseClasses(NIBittensorChatModel)] + this.inputs = [ + { + label: 'System prompt', + name: 'system_prompt', + type: 'string', + additionalParams: true, + optional: true + }, + ] + + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const system_prompt = nodeData.inputs?.system_prompt as string + const obj: Partial = { + systemPrompt: system_prompt, + } + + const model = new NIBittensorChatModel(obj) + return model + } +} + +module.exports = { nodeClass: Bittensor_ChatModels } diff --git a/packages/components/nodes/chatmodels/Bittensor/logo.png b/packages/components/nodes/chatmodels/Bittensor/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ad51774d5198772b36f6bd19aa8f8404f5906698 GIT binary patch literal 24561 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 F{{W%y8Djtd literal 0 HcmV?d00001 diff --git a/packages/components/nodes/llms/Bittensor/Bittensor.ts b/packages/components/nodes/llms/Bittensor/Bittensor.ts new file mode 100644 index 00000000..86b400a4 --- /dev/null +++ b/packages/components/nodes/llms/Bittensor/Bittensor.ts @@ -0,0 +1,58 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import {NIBittensorLLM, BittensorInput} from 'langchain/experimental/llms/bittensor'; + +class Bittensor_LLMs implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'NIBittensorLLM' + this.name = 'NIBittensorLLM' + this.version = 1.0 + this.type = 'Bittensor' + this.icon = 'logo.png' + this.category = 'LLMs' + this.description = 'Wrapper around Bittensor subnet 1 large language models' + this.baseClasses = [this.type, ...getBaseClasses(NIBittensorLLM)] + this.inputs = [ + { + label: 'System prompt', + name: 'system_prompt', + type: 'string', + additionalParams: true, + optional: true + }, + { + label: 'Top Responses', + name: 'topResponses', + type: 'number', + step: 1, + optional: true, + additionalParams: true + } + ] + + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const system_prompt = nodeData.inputs?.system_prompt as string + const topResponses = Number(nodeData.inputs?.topResponses as number); + const obj: Partial = { + systemPrompt: system_prompt, + topResponses: topResponses, + } + + const model = new NIBittensorLLM(obj) + return model + } +} + +module.exports = { nodeClass: Bittensor_LLMs } diff --git a/packages/components/nodes/llms/Bittensor/logo.png b/packages/components/nodes/llms/Bittensor/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ad51774d5198772b36f6bd19aa8f8404f5906698 GIT binary patch literal 24561 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 F{{W%y8Djtd literal 0 HcmV?d00001 From 37d8b3f310e40a12f79eb289e48640a2d43e6add Mon Sep 17 00:00:00 2001 From: BitVoyagerMan Date: Thu, 21 Sep 2023 07:12:28 -0400 Subject: [PATCH 02/55] fix lint --- .../nodes/chatmodels/Bittensor/Bittensor.ts | 12 +++++------- .../components/nodes/llms/Bittensor/Bittensor.ts | 11 +++++------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts index 8ca05634..cfcac863 100644 --- a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts +++ b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts @@ -1,6 +1,6 @@ -import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' -import {NIBittensorChatModel, BittensorInput} from 'langchain/experimental/chat_models/bittensor'; +import { NIBittensorChatModel, BittensorInput } from 'langchain/experimental/chat_models/bittensor' class Bittensor_ChatModels implements INode { label: string @@ -29,17 +29,15 @@ class Bittensor_ChatModels implements INode { type: 'string', additionalParams: true, optional: true - }, + } ] - } - async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string const obj: Partial = { - systemPrompt: system_prompt, + systemPrompt: system_prompt } - const model = new NIBittensorChatModel(obj) return model } diff --git a/packages/components/nodes/llms/Bittensor/Bittensor.ts b/packages/components/nodes/llms/Bittensor/Bittensor.ts index 86b400a4..a87a7e48 100644 --- a/packages/components/nodes/llms/Bittensor/Bittensor.ts +++ b/packages/components/nodes/llms/Bittensor/Bittensor.ts @@ -1,6 +1,6 @@ -import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' -import {NIBittensorLLM, BittensorInput} from 'langchain/experimental/llms/bittensor'; +import { NIBittensorLLM, BittensorInput } from 'langchain/experimental/llms/bittensor' class Bittensor_LLMs implements INode { label: string @@ -39,15 +39,14 @@ class Bittensor_LLMs implements INode { additionalParams: true } ] - } - async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string - const topResponses = Number(nodeData.inputs?.topResponses as number); + const topResponses = Number(nodeData.inputs?.topResponses as number) const obj: Partial = { systemPrompt: system_prompt, - topResponses: topResponses, + topResponses: topResponses } const model = new NIBittensorLLM(obj) From ce9b9ad8ca2b2db423601a50ad977b11f015ab41 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 21 Sep 2023 21:54:03 +0100 Subject: [PATCH 03/55] add env variable to start.ts --- packages/server/src/commands/start.ts | 2 ++ packages/server/src/utils/rateLimit.ts | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/server/src/commands/start.ts b/packages/server/src/commands/start.ts index b9ea970d..6bf7d699 100644 --- a/packages/server/src/commands/start.ts +++ b/packages/server/src/commands/start.ts @@ -27,6 +27,7 @@ export default class Start extends Command { LOG_LEVEL: Flags.string(), TOOL_FUNCTION_BUILTIN_DEP: Flags.string(), TOOL_FUNCTION_EXTERNAL_DEP: Flags.string(), + NUMBER_OF_PROXIES: Flags.string(), DATABASE_TYPE: Flags.string(), DATABASE_PATH: Flags.string(), DATABASE_PORT: Flags.string(), @@ -72,6 +73,7 @@ export default class Start extends Command { if (flags.PORT) process.env.PORT = flags.PORT if (flags.DEBUG) process.env.DEBUG = flags.DEBUG + if (flags.NUMBER_OF_PROXIES) process.env.NUMBER_OF_PROXIES = flags.NUMBER_OF_PROXIES // Authorization if (flags.FLOWISE_USERNAME) process.env.FLOWISE_USERNAME = flags.FLOWISE_USERNAME diff --git a/packages/server/src/utils/rateLimit.ts b/packages/server/src/utils/rateLimit.ts index b1cd1819..68b5b693 100644 --- a/packages/server/src/utils/rateLimit.ts +++ b/packages/server/src/utils/rateLimit.ts @@ -12,7 +12,7 @@ async function addRateLimiter(id: string, duration: number, limit: number, messa rateLimiters[id] = rateLimit({ windowMs: duration * 1000, max: limit, - handler: (req, res) => { + handler: (_, res) => { res.status(429).send(message) } }) @@ -33,15 +33,19 @@ export function getRateLimiter(req: Request, res: Response, next: NextFunction) export async function createRateLimiter(chatFlow: IChatFlow) { if (!chatFlow.apiConfig) return - const apiConfig: any = JSON.parse(chatFlow.apiConfig) + const apiConfig = JSON.parse(chatFlow.apiConfig) + const rateLimit: { limitDuration: number; limitMax: number; limitMsg: string } = apiConfig.rateLimit if (!rateLimit) return + const { limitDuration, limitMax, limitMsg } = rateLimit if (limitMax && limitDuration && limitMsg) await addRateLimiter(chatFlow.id, limitDuration, limitMax, limitMsg) } export async function initializeRateLimiter(chatFlowPool: IChatFlow[]) { - await chatFlowPool.map(async (chatFlow) => { - await createRateLimiter(chatFlow) - }) + await Promise.all( + chatFlowPool.map(async (chatFlow) => { + await createRateLimiter(chatFlow) + }) + ) } From 88f0fe9598c0a15fe34d09dfd8f7bf2bcb7b4253 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 21 Sep 2023 22:08:45 +0100 Subject: [PATCH 04/55] chroma authorization --- packages/components/nodes/vectorstores/Chroma/core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/vectorstores/Chroma/core.ts b/packages/components/nodes/vectorstores/Chroma/core.ts index 8277c58e..b1bf9cc7 100644 --- a/packages/components/nodes/vectorstores/Chroma/core.ts +++ b/packages/components/nodes/vectorstores/Chroma/core.ts @@ -30,7 +30,7 @@ export class ChromaExtended extends Chroma { if (this.chromaApiKey) { obj.fetchOptions = { headers: { - 'X-Api-Key': this.chromaApiKey + Authorization: `Bearer ${this.chromaApiKey}` } } } From ea4d3d0278a1c1137bf538c88218b348d6a36521 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 25 Sep 2023 11:32:31 +0100 Subject: [PATCH 05/55] update fields --- .../SqlDatabaseChain/SqlDatabaseChain.ts | 8 ++-- .../marketplaces/chatflows/SQL DB Chain.json | 42 ++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts index 5d270fd8..ba9cd7f8 100644 --- a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts +++ b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts @@ -43,7 +43,7 @@ class SqlDatabaseChain_Chains implements INode { constructor() { this.label = 'Sql Database Chain' this.name = 'sqlDatabaseChain' - this.version = 3.0 + this.version = 4.0 this.type = 'SqlDatabaseChain' this.icon = 'sqlchain.svg' this.category = 'Chains' @@ -89,7 +89,8 @@ class SqlDatabaseChain_Chains implements INode { label: 'Include Tables', name: 'includesTables', type: 'string', - description: 'Tables to include for queries.', + description: 'Tables to include for queries, seperated by comma. Can only use Include Tables or Ignore Tables', + placeholder: 'table1, table2', additionalParams: true, optional: true }, @@ -97,7 +98,8 @@ class SqlDatabaseChain_Chains implements INode { label: 'Ignore Tables', name: 'ignoreTables', type: 'string', - description: 'Tables to ignore for queries.', + description: 'Tables to ignore for queries, seperated by comma. Can only use Ignore Tables or Include Tables', + placeholder: 'table1, table2', additionalParams: true, optional: true }, diff --git a/packages/server/marketplaces/chatflows/SQL DB Chain.json b/packages/server/marketplaces/chatflows/SQL DB Chain.json index acec5432..646db5d4 100644 --- a/packages/server/marketplaces/chatflows/SQL DB Chain.json +++ b/packages/server/marketplaces/chatflows/SQL DB Chain.json @@ -167,7 +167,7 @@ "data": { "id": "sqlDatabaseChain_0", "label": "Sql Database Chain", - "version": 2, + "version": 4, "name": "sqlDatabaseChain", "type": "SqlDatabaseChain", "baseClasses": ["SqlDatabaseChain", "BaseChain", "Runnable"], @@ -206,6 +206,46 @@ "placeholder": "1270.0.0.1:5432/chinook", "id": "sqlDatabaseChain_0-input-url-string" }, + { + "label": "Include Tables", + "name": "includesTables", + "type": "string", + "description": "Tables to include for queries, seperated by comma. Can only use Include Tables or Ignore Tables", + "placeholder": "table1, table2", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-includesTables-string" + }, + { + "label": "Ignore Tables", + "name": "ignoreTables", + "type": "string", + "description": "Tables to ignore for queries, seperated by comma. Can only use Ignore Tables or Include Tables", + "placeholder": "table1, table2", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-ignoreTables-string" + }, + { + "label": "Sample table's rows info", + "name": "sampleRowsInTableInfo", + "type": "number", + "description": "Number of sample row for tables to load for info.", + "placeholder": "3", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-sampleRowsInTableInfo-number" + }, + { + "label": "Top Keys", + "name": "topK", + "type": "number", + "description": "If you are querying for several rows of a table you can select the maximum number of results you want to get by using the top_k parameter (default is 10). This is useful for avoiding query results that exceed the prompt max length or consume tokens unnecessarily.", + "placeholder": "10", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-topK-number" + }, { "label": "Custom Prompt", "name": "customPrompt", From 5574e82a029307a9926ebdc584d90dd500f1dc7b Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 28 Sep 2023 11:04:01 +0100 Subject: [PATCH 06/55] update rate limit guide link --- packages/ui/src/views/chatflows/Configuration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/views/chatflows/Configuration.js b/packages/ui/src/views/chatflows/Configuration.js index 51b8d61c..d569020b 100644 --- a/packages/ui/src/views/chatflows/Configuration.js +++ b/packages/ui/src/views/chatflows/Configuration.js @@ -136,7 +136,7 @@ const Configuration = () => { Rate Limit Setup Guide to set up Rate Limit correctly in your hosting environment.' + 'Visit Rate Limit Setup Guide to set up Rate Limit correctly in your hosting environment.' } /> From d588ac0480846271e00324caf413cd408eb5d19e Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 29 Sep 2023 07:54:16 +0530 Subject: [PATCH 07/55] Adding support for LLM Caching. --- .../LocalMemoryCache/LocalMemoryCache.ts | 44 ++++++++++++++++++ .../llmcache/LocalMemoryCache/memorycache.png | Bin 0 -> 2717 bytes .../components/nodes/llms/OpenAI/OpenAI.ts | 17 +++++-- packages/components/package.json | 2 +- packages/components/src/Interface.ts | 7 +++ packages/components/src/handler.ts | 22 ++++++++- 6 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts create mode 100644 packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts b/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts new file mode 100644 index 00000000..73f4415e --- /dev/null +++ b/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts @@ -0,0 +1,44 @@ +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { InMemoryCache } from 'langchain/cache' +import { getBaseClasses } from '../../../src' + +class LocalMemoryCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + inMemoryCache: any + + constructor() { + this.label = 'Local (Builtin) Cache' + this.name = 'localCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'memorycache.png' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(InMemoryCache)] + } + ] + } + + async init(nodeData: INodeData): Promise { + if (!this.inMemoryCache) { + this.inMemoryCache = InMemoryCache.global() + } + return this.inMemoryCache + } +} + +module.exports = { nodeClass: LocalMemoryCache } diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png b/packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png new file mode 100644 index 0000000000000000000000000000000000000000..aaeecd6fb100be3a10b3d1faca046f9fa409f018 GIT binary patch literal 2717 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 XQt;1#;KI))00000NkvXXu0mjfl~Wzs literal 0 HcmV?d00001 diff --git a/packages/components/nodes/llms/OpenAI/OpenAI.ts b/packages/components/nodes/llms/OpenAI/OpenAI.ts index 2960ad2a..9fa61653 100644 --- a/packages/components/nodes/llms/OpenAI/OpenAI.ts +++ b/packages/components/nodes/llms/OpenAI/OpenAI.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { OpenAI, OpenAIInput } from 'langchain/llms/openai' +import { BaseLLMParams } from 'langchain/dist/llms/base' +import { BaseCache } from 'langchain/schema' class OpenAI_LLMs implements INode { label: string @@ -17,7 +19,7 @@ class OpenAI_LLMs implements INode { constructor() { this.label = 'OpenAI' this.name = 'openAI' - this.version = 2.0 + this.version = 3.0 this.type = 'OpenAI' this.icon = 'openai.png' this.category = 'LLMs' @@ -30,6 +32,12 @@ class OpenAI_LLMs implements INode { credentialNames: ['openAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -149,7 +157,9 @@ class OpenAI_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const obj: Partial & { openAIApiKey?: string } = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey, @@ -164,8 +174,9 @@ class OpenAI_LLMs implements INode { if (batchSize) obj.batchSize = parseInt(batchSize, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) - let parsedBaseOptions: any | undefined = undefined + if (llmCache) obj.cache = llmCache + let parsedBaseOptions: any | undefined = undefined if (baseOptions) { try { parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions) diff --git a/packages/components/package.json b/packages/components/package.json index 93609106..f8498e31 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -42,7 +42,7 @@ "google-auth-library": "^9.0.0", "graphql": "^16.6.0", "html-to-text": "^9.0.5", - "langchain": "^0.0.152", + "langchain": "^0.0.154", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index e883d056..76dc7354 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -1,6 +1,7 @@ /** * Types */ +import { BaseCache } from 'langchain/schema' export type NodeParamsType = | 'asyncOptions' @@ -176,3 +177,9 @@ export class VectorStoreRetriever { this.vectorStore = fields.vectorStore } } + +export interface LLMCacheBase { + name: string + description: string + baseCache: BaseCache +} diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 10f9a214..a102b473 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -151,6 +151,7 @@ export class CustomChainHandler extends BaseCallbackHandler { socketIOClientId = '' skipK = 0 // Skip streaming for first K numbers of handleLLMStart returnSourceDocuments = false + cachedResponse = true constructor(socketIO: Server, socketIOClientId: string, skipK?: number, returnSourceDocuments?: boolean) { super() @@ -161,6 +162,7 @@ export class CustomChainHandler extends BaseCallbackHandler { } handleLLMStart() { + this.cachedResponse = false if (this.skipK > 0) this.skipK -= 1 } @@ -175,13 +177,31 @@ export class CustomChainHandler extends BaseCallbackHandler { } handleLLMEnd() { - this.socketIO.to(this.socketIOClientId).emit('end') + /* send the end event from handleChainEnd */ + // this.socketIO.to(this.socketIOClientId).emit('end') } handleChainEnd(outputs: ChainValues): void | Promise { if (this.returnSourceDocuments) { this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) } + /* + Langchain does not call handleLLMStart, handleLLMEnd, handleLLMNewToken when the chain is cached. + Callback Order is "Chain Start -> LLM Start --> LLM Token --> LLM End -> Chain End" for normal responses. + Callback Order is "Chain Start -> Chain End" for cached responses. + */ + if (this.cachedResponse) { + const cachedValue = outputs.text as string + //split at whitespace, and keep the whitespace. This is to preserve the original formatting. + const result = cachedValue.split(/(\s+)/) + result.forEach((token: string, index: number) => { + if (index === 0) { + this.socketIO.to(this.socketIOClientId).emit('start', token) + } + this.socketIO.to(this.socketIOClientId).emit('token', token) + }) + } + this.socketIO.to(this.socketIOClientId).emit('end') } } From d81869fd59de2894f15b1649a909d4e513393302 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 29 Sep 2023 08:19:44 +0530 Subject: [PATCH 08/55] Extending support for Caching to all LLM's. --- .../nodes/llms/Azure OpenAI/AzureOpenAI.ts | 16 +++++++++++++--- .../components/nodes/llms/Bittensor/Bittensor.ts | 15 +++++++++++++-- packages/components/nodes/llms/Cohere/Cohere.ts | 13 ++++++++++--- .../nodes/llms/GooglePaLM/GooglePaLM.ts | 12 ++++++++++-- .../nodes/llms/GoogleVertexAI/GoogleVertexAI.ts | 11 ++++++++++- .../HuggingFaceInference/HuggingFaceInference.ts | 13 ++++++++++++- packages/components/nodes/llms/OpenAI/OpenAI.ts | 2 +- .../components/nodes/llms/Replicate/Replicate.ts | 16 ++++++++++++++-- 8 files changed, 83 insertions(+), 15 deletions(-) diff --git a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts index f48c4642..e5cca769 100644 --- a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts +++ b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts @@ -1,7 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { AzureOpenAIInput, OpenAI, OpenAIInput } from 'langchain/llms/openai' - +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class AzureOpenAI_LLMs implements INode { label: string name: string @@ -17,7 +18,7 @@ class AzureOpenAI_LLMs implements INode { constructor() { this.label = 'Azure OpenAI' this.name = 'azureOpenAI' - this.version = 1.0 + this.version = 2.0 this.type = 'AzureOpenAI' this.icon = 'Azure.svg' this.category = 'LLMs' @@ -30,6 +31,12 @@ class AzureOpenAI_LLMs implements INode { credentialNames: ['azureOpenAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -163,7 +170,9 @@ class AzureOpenAI_LLMs implements INode { const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData) const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData) - const obj: Partial & Partial = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams & Partial = { temperature: parseFloat(temperature), modelName, azureOpenAIApiKey, @@ -179,6 +188,7 @@ class AzureOpenAI_LLMs implements INode { if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) + if (llmCache) obj.cache = llmCache const model = new OpenAI(obj) return model diff --git a/packages/components/nodes/llms/Bittensor/Bittensor.ts b/packages/components/nodes/llms/Bittensor/Bittensor.ts index a87a7e48..84401e59 100644 --- a/packages/components/nodes/llms/Bittensor/Bittensor.ts +++ b/packages/components/nodes/llms/Bittensor/Bittensor.ts @@ -1,6 +1,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { NIBittensorLLM, BittensorInput } from 'langchain/experimental/llms/bittensor' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class Bittensor_LLMs implements INode { label: string @@ -16,13 +18,19 @@ class Bittensor_LLMs implements INode { constructor() { this.label = 'NIBittensorLLM' this.name = 'NIBittensorLLM' - this.version = 1.0 + this.version = 2.0 this.type = 'Bittensor' this.icon = 'logo.png' this.category = 'LLMs' this.description = 'Wrapper around Bittensor subnet 1 large language models' this.baseClasses = [this.type, ...getBaseClasses(NIBittensorLLM)] this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'System prompt', name: 'system_prompt', @@ -44,10 +52,13 @@ class Bittensor_LLMs implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string const topResponses = Number(nodeData.inputs?.topResponses as number) - const obj: Partial = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams = { systemPrompt: system_prompt, topResponses: topResponses } + if (llmCache) obj.cache = llmCache const model = new NIBittensorLLM(obj) return model diff --git a/packages/components/nodes/llms/Cohere/Cohere.ts b/packages/components/nodes/llms/Cohere/Cohere.ts index 4a3a8a80..8b4c0ac2 100644 --- a/packages/components/nodes/llms/Cohere/Cohere.ts +++ b/packages/components/nodes/llms/Cohere/Cohere.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { Cohere, CohereInput } from './core' +import { BaseCache } from 'langchain/schema' class Cohere_LLMs implements INode { label: string @@ -17,7 +18,7 @@ class Cohere_LLMs implements INode { constructor() { this.label = 'Cohere' this.name = 'cohere' - this.version = 1.0 + this.version = 2.0 this.type = 'Cohere' this.icon = 'cohere.png' this.category = 'LLMs' @@ -30,6 +31,12 @@ class Cohere_LLMs implements INode { credentialNames: ['cohereApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -85,7 +92,7 @@ class Cohere_LLMs implements INode { const temperature = nodeData.inputs?.temperature as string const modelName = nodeData.inputs?.modelName as string const maxTokens = nodeData.inputs?.maxTokens as string - + const llmCache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) @@ -96,7 +103,7 @@ class Cohere_LLMs implements INode { if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) if (modelName) obj.model = modelName if (temperature) obj.temperature = parseFloat(temperature) - + if (llmCache) obj.cache = llmCache const model = new Cohere(obj) return model } diff --git a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts index 24630360..d916c09f 100644 --- a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts +++ b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts @@ -1,7 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { GooglePaLM, GooglePaLMTextInput } from 'langchain/llms/googlepalm' - +import { BaseCache } from 'langchain/schema' class GooglePaLM_LLMs implements INode { label: string name: string @@ -17,7 +17,7 @@ class GooglePaLM_LLMs implements INode { constructor() { this.label = 'GooglePaLM' this.name = 'GooglePaLM' - this.version = 1.0 + this.version = 2.0 this.type = 'GooglePaLM' this.icon = 'Google_PaLM_Logo.svg' this.category = 'LLMs' @@ -30,6 +30,12 @@ class GooglePaLM_LLMs implements INode { credentialNames: ['googleMakerSuite'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -126,6 +132,7 @@ class GooglePaLM_LLMs implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const stopSequencesObj = nodeData.inputs?.stopSequencesObj + const llmCache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) @@ -139,6 +146,7 @@ class GooglePaLM_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) + if (llmCache) obj.cache = llmCache let parsedStopSequences: any | undefined = undefined if (stopSequencesObj) { diff --git a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts index 4d19d04f..41b18475 100644 --- a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts +++ b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts @@ -2,6 +2,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { GoogleVertexAI, GoogleVertexAITextInput } from 'langchain/llms/googlevertexai' import { GoogleAuthOptions } from 'google-auth-library' +import { BaseCache } from 'langchain/schema' class GoogleVertexAI_LLMs implements INode { label: string @@ -18,7 +19,7 @@ class GoogleVertexAI_LLMs implements INode { constructor() { this.label = 'GoogleVertexAI' this.name = 'googlevertexai' - this.version = 1.0 + this.version = 2.0 this.type = 'GoogleVertexAI' this.icon = 'vertexai.svg' this.category = 'LLMs' @@ -34,6 +35,12 @@ class GoogleVertexAI_LLMs implements INode { 'Google Vertex AI credential. If you are using a GCP service like Cloud Run, or if you have installed default credentials on your local machine, you do not need to set this credential.' } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -120,6 +127,7 @@ class GoogleVertexAI_LLMs implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string + const llmCache = nodeData.inputs?.llmCache as BaseCache const obj: Partial = { temperature: parseFloat(temperature), @@ -129,6 +137,7 @@ class GoogleVertexAI_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) + if (llmCache) obj.cache = llmCache const model = new GoogleVertexAI(obj) return model diff --git a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts index c7f6a37e..9d6226e2 100644 --- a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts +++ b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { HFInput, HuggingFaceInference } from './core' +import { BaseCache } from 'langchain/schema' class HuggingFaceInference_LLMs implements INode { label: string @@ -17,7 +18,7 @@ class HuggingFaceInference_LLMs implements INode { constructor() { this.label = 'HuggingFace Inference' this.name = 'huggingFaceInference_LLMs' - this.version = 1.0 + this.version = 2.0 this.type = 'HuggingFaceInference' this.icon = 'huggingface.png' this.category = 'LLMs' @@ -30,6 +31,12 @@ class HuggingFaceInference_LLMs implements INode { credentialNames: ['huggingFaceApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model', name: 'model', @@ -106,6 +113,8 @@ class HuggingFaceInference_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) + const llmCache = nodeData.inputs?.llmCache as BaseCache + const obj: Partial = { model, apiKey: huggingFaceApiKey @@ -119,6 +128,8 @@ class HuggingFaceInference_LLMs implements INode { if (endpoint) obj.endpoint = endpoint const huggingFace = new HuggingFaceInference(obj) + if (llmCache) huggingFace.cache = llmCache + return huggingFace } } diff --git a/packages/components/nodes/llms/OpenAI/OpenAI.ts b/packages/components/nodes/llms/OpenAI/OpenAI.ts index 9fa61653..607ebeb4 100644 --- a/packages/components/nodes/llms/OpenAI/OpenAI.ts +++ b/packages/components/nodes/llms/OpenAI/OpenAI.ts @@ -1,7 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { OpenAI, OpenAIInput } from 'langchain/llms/openai' -import { BaseLLMParams } from 'langchain/dist/llms/base' +import { BaseLLMParams } from 'langchain/llms/base' import { BaseCache } from 'langchain/schema' class OpenAI_LLMs implements INode { diff --git a/packages/components/nodes/llms/Replicate/Replicate.ts b/packages/components/nodes/llms/Replicate/Replicate.ts index 22c6e93a..fd1eb6f7 100644 --- a/packages/components/nodes/llms/Replicate/Replicate.ts +++ b/packages/components/nodes/llms/Replicate/Replicate.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { Replicate, ReplicateInput } from 'langchain/llms/replicate' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class Replicate_LLMs implements INode { label: string @@ -17,7 +19,7 @@ class Replicate_LLMs implements INode { constructor() { this.label = 'Replicate' this.name = 'replicate' - this.version = 1.0 + this.version = 2.0 this.type = 'Replicate' this.icon = 'replicate.svg' this.category = 'LLMs' @@ -30,6 +32,12 @@ class Replicate_LLMs implements INode { credentialNames: ['replicateApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model', name: 'model', @@ -103,7 +111,9 @@ class Replicate_LLMs implements INode { const name = modelName.split(':')[0].split('/').pop() const org = modelName.split(':')[0].split('/')[0] - const obj: ReplicateInput = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: ReplicateInput & BaseLLMParams = { model: `${org}/${name}:${version}`, apiKey } @@ -120,6 +130,8 @@ class Replicate_LLMs implements INode { } if (Object.keys(inputs).length) obj.input = inputs + if (llmCache) obj.cache = llmCache + const model = new Replicate(obj) return model } From 18702e4c479916ac409fd136d1b13aba85a6ed29 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Sep 2023 12:05:51 +0530 Subject: [PATCH 09/55] Refactoring of LLM In Cache Memory files for better clarity of name --- .../LLMInMemoryCache.ts} | 4 ++-- .../memorycache.png | Bin 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/components/nodes/llmcache/{LocalMemoryCache/LocalMemoryCache.ts => LLMInMemoryCache/LLMInMemoryCache.ts} (92%) rename packages/components/nodes/llmcache/{LocalMemoryCache => LLMInMemoryCache}/memorycache.png (100%) diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts similarity index 92% rename from packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts rename to packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts index 73f4415e..5e77a029 100644 --- a/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts +++ b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts @@ -2,7 +2,7 @@ import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/I import { InMemoryCache } from 'langchain/cache' import { getBaseClasses } from '../../../src' -class LocalMemoryCache implements INode { +class LLMInMemoryCache implements INode { label: string name: string version: number @@ -41,4 +41,4 @@ class LocalMemoryCache implements INode { } } -module.exports = { nodeClass: LocalMemoryCache } +module.exports = { nodeClass: LLMInMemoryCache } diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png b/packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png similarity index 100% rename from packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png rename to packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png From 4efec94dc8d404755379a8068628341870c5da04 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Sep 2023 12:07:48 +0530 Subject: [PATCH 10/55] LLM Cache - Addition of Momento Cache --- .../credentials/MomentoCacheApi.credential.ts | 36 +++++++++ .../LLMMomentoCache/LLMMomentoCache.ts | 75 ++++++++++++++++++ .../llmcache/LLMMomentoCache/momento.png | Bin 0 -> 5534 bytes packages/components/package.json | 1 + 4 files changed, 112 insertions(+) create mode 100644 packages/components/credentials/MomentoCacheApi.credential.ts create mode 100644 packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts create mode 100644 packages/components/nodes/llmcache/LLMMomentoCache/momento.png diff --git a/packages/components/credentials/MomentoCacheApi.credential.ts b/packages/components/credentials/MomentoCacheApi.credential.ts new file mode 100644 index 00000000..038f826d --- /dev/null +++ b/packages/components/credentials/MomentoCacheApi.credential.ts @@ -0,0 +1,36 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class MomentoCacheApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Momento Cache API' + this.name = 'momentoCacheApi' + this.version = 1.0 + this.description = + 'Refer to official guide on how to get API key on Momento' + this.inputs = [ + { + label: 'Cache', + name: 'momentoCache', + type: 'string' + }, + { + label: 'API Key', + name: 'momentoApiKey', + type: 'password' + }, + { + label: 'Endpoint', + name: 'momentoEndpoint', + type: 'string' + } + ] + } +} + +module.exports = { credClass: MomentoCacheApi } diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts new file mode 100644 index 00000000..82267c24 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts @@ -0,0 +1,75 @@ +import { + getBaseClasses, + getCredentialData, + getCredentialParam, + ICommonObject, + INode, + INodeData, + INodeOutputsValue, + INodeParams +} from '../../../src' +import { MomentoCache } from 'langchain/cache/momento' +import { CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk' + +class LLMMomentoCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + credential: INodeParams + + constructor() { + this.label = 'Momento Cache' + this.name = 'momentoCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'momento.png' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['momentoCacheApi'] + } + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(MomentoCache)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const apiKey = getCredentialParam('momentoApiKey', credentialData, nodeData) + const cacheName = getCredentialParam('momentoCache', credentialData, nodeData) + const endPoint = getCredentialParam('momentoEndpoint', credentialData, nodeData) + + // See https://github.com/momentohq/client-sdk-javascript for connection options + const client = new CacheClient({ + configuration: Configurations.Laptop.v1(), + credentialProvider: CredentialProvider.fromString({ + apiKey: apiKey + }), + defaultTtlSeconds: 60 * 60 * 24 + }) + + let momentoCache = await MomentoCache.fromProps({ + client, + cacheName: cacheName + }) + return momentoCache + } +} + +module.exports = { nodeClass: LLMMomentoCache } diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/momento.png b/packages/components/nodes/llmcache/LLMMomentoCache/momento.png new file mode 100644 index 0000000000000000000000000000000000000000..0f2b54b6a0c0e6100d2546d053e0b4548c42e4c6 GIT binary patch literal 5534 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 literal 0 HcmV?d00001 diff --git a/packages/components/package.json b/packages/components/package.json index f8498e31..18bf8e6a 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -19,6 +19,7 @@ "@aws-sdk/client-dynamodb": "^3.360.0", "@dqbd/tiktoken": "^1.0.7", "@getzep/zep-js": "^0.6.3", + "@gomomento/sdk": "^1.40.2", "@google-ai/generativelanguage": "^0.2.1", "@huggingface/inference": "^2.6.1", "@notionhq/client": "^2.2.8", From 29be2d2608de2e7c21b762041409aab8b827cb7d Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Sep 2023 18:51:14 +0530 Subject: [PATCH 11/55] Addition of Redis LLM Cache --- .../credentials/RedisCacheApi.credential.ts | 43 +++++++++++ .../llmcache/LLMRedisCache/LLMRedisCache.ts | 75 +++++++++++++++++++ .../nodes/llmcache/LLMRedisCache/redis.svg | 1 + packages/components/package.json | 1 + 4 files changed, 120 insertions(+) create mode 100644 packages/components/credentials/RedisCacheApi.credential.ts create mode 100644 packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts create mode 100644 packages/components/nodes/llmcache/LLMRedisCache/redis.svg diff --git a/packages/components/credentials/RedisCacheApi.credential.ts b/packages/components/credentials/RedisCacheApi.credential.ts new file mode 100644 index 00000000..e09a94e7 --- /dev/null +++ b/packages/components/credentials/RedisCacheApi.credential.ts @@ -0,0 +1,43 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class RedisCacheApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Redis Cache API' + this.name = 'redisCacheApi' + this.version = 1.0 + this.inputs = [ + { + label: 'Redis Host', + name: 'redisCacheHost', + type: 'string', + default: '127.0.0.1' + }, + { + label: 'Port', + name: 'redisCachePort', + type: 'number', + default: '6789' + }, + { + label: 'User', + name: 'redisCacheUser', + type: 'string', + placeholder: '' + }, + { + label: 'Password', + name: 'redisCachePwd', + type: 'password', + placeholder: '' + } + ] + } +} + +module.exports = { credClass: RedisCacheApi } diff --git a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts new file mode 100644 index 00000000..4a098e82 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts @@ -0,0 +1,75 @@ +import { + getBaseClasses, + getCredentialData, + getCredentialParam, + ICommonObject, + INode, + INodeData, + INodeOutputsValue, + INodeParams +} from '../../../src' +import { RedisCache } from 'langchain/cache/ioredis' +import { Redis } from 'ioredis' + +class LLMRedisCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + credential: INodeParams + + constructor() { + this.label = 'Redis LLM Cache' + this.name = 'redisCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'redis.svg' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['redisCacheApi'] + } + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(RedisCache)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const username = getCredentialParam('redisCacheUser', credentialData, nodeData) + const password = getCredentialParam('redisCachePwd', credentialData, nodeData) + const portStr = getCredentialParam('redisCachePort', credentialData, nodeData) + const host = getCredentialParam('redisCacheHost', credentialData, nodeData) + let port = 6379 + try { + port = portStr ? parseInt(portStr) : 6379 + } catch (e) { + port = 6379 + } + + const client = new Redis({ + port: port, // Redis port + host: host, + username: username, + password: password + }) + return new RedisCache(client) + } +} + +module.exports = { nodeClass: LLMRedisCache } diff --git a/packages/components/nodes/llmcache/LLMRedisCache/redis.svg b/packages/components/nodes/llmcache/LLMRedisCache/redis.svg new file mode 100644 index 00000000..90359069 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMRedisCache/redis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/package.json b/packages/components/package.json index 18bf8e6a..5e993f86 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -43,6 +43,7 @@ "google-auth-library": "^9.0.0", "graphql": "^16.6.0", "html-to-text": "^9.0.5", + "ioredis": "^5.3.2", "langchain": "^0.0.154", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", From ca31d88a1405cba2f44b06316158625b686917fa Mon Sep 17 00:00:00 2001 From: vincent-pli Date: Mon, 2 Oct 2023 09:03:22 +0800 Subject: [PATCH 12/55] duplicate icon when market is empty --- packages/ui/src/views/marketplaces/index.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/ui/src/views/marketplaces/index.js b/packages/ui/src/views/marketplaces/index.js index a7836161..49c692db 100644 --- a/packages/ui/src/views/marketplaces/index.js +++ b/packages/ui/src/views/marketplaces/index.js @@ -175,19 +175,8 @@ const Marketplace = () => { )} ))} - {!isChatflowsLoading && (!getAllChatflowsMarketplacesApi.data || getAllChatflowsMarketplacesApi.data.length === 0) && ( - - - WorkflowEmptySVG - -
No Marketplace Yet
-
- )} - {!isToolsLoading && (!getAllToolsMarketplacesApi.data || getAllToolsMarketplacesApi.data.length === 0) && ( + {((!isChatflowsLoading && (!getAllChatflowsMarketplacesApi.data || getAllChatflowsMarketplacesApi.data.length === 0)) || + (!isToolsLoading && (!getAllToolsMarketplacesApi.data || getAllToolsMarketplacesApi.data.length === 0))) && ( Date: Mon, 2 Oct 2023 08:47:47 -0400 Subject: [PATCH 13/55] Update langchain to 0.0.157 for AWS Bedrock GA support --- 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 93609106..ba63cb92 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -42,7 +42,7 @@ "google-auth-library": "^9.0.0", "graphql": "^16.6.0", "html-to-text": "^9.0.5", - "langchain": "^0.0.152", + "langchain": "^0.0.157", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", From f836e77e7b3e670e9cc8234456c61004b125310c Mon Sep 17 00:00:00 2001 From: Brian Krygsman Date: Mon, 2 Oct 2023 08:44:14 -0400 Subject: [PATCH 14/55] Add AWS credentials support --- .../credentials/AWSCredential.credential.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 packages/components/credentials/AWSCredential.credential.ts diff --git a/packages/components/credentials/AWSCredential.credential.ts b/packages/components/credentials/AWSCredential.credential.ts new file mode 100644 index 00000000..3c9dd3a6 --- /dev/null +++ b/packages/components/credentials/AWSCredential.credential.ts @@ -0,0 +1,47 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class AWSApi implements INodeCredential { + label: string + name: string + version: number + description: string + optional: boolean + inputs: INodeParams[] + + constructor() { + this.label = 'AWS security credentials' + this.name = 'awsApi' + this.version = 1.0 + this.description = + 'Your AWS security credentials. When unspecified, credentials will be sourced from the runtime environment according to the default AWS SDK behavior.' + this.optional = true + this.inputs = [ + { + label: 'AWS Access Key', + name: 'awsKey', + type: 'string', + placeholder: '', + description: 'The access key for your AWS account.', + optional: true + }, + { + label: 'AWS Secret Access Key', + name: 'awsSecret', + type: 'password', + placeholder: '', + description: 'The secret key for your AWS account.', + optional: true + }, + { + label: 'AWS Session Key', + name: 'awsSession', + type: 'password', + placeholder: '', + description: 'The session key for your AWS account. This is only needed when you are using temporary credentials.', + optional: true + } + ] + } +} + +module.exports = { credClass: AWSApi } From ca6b0f2b22bfba448f3b4a02c3baebfcf9968a5d Mon Sep 17 00:00:00 2001 From: Brian Krygsman Date: Mon, 2 Oct 2023 08:45:02 -0400 Subject: [PATCH 15/55] Add AWS Bedrock LLM support. Note: stop sequences parameter not yet implemented. --- .../nodes/llms/AWSBedrock/AWSBedrock.ts | 166 ++++++++++++++++++ .../nodes/llms/AWSBedrock/awsBedrock.png | Bin 0 -> 62897 bytes 2 files changed, 166 insertions(+) create mode 100644 packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts create mode 100644 packages/components/nodes/llms/AWSBedrock/awsBedrock.png diff --git a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts new file mode 100644 index 00000000..68ee7ed2 --- /dev/null +++ b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts @@ -0,0 +1,166 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { Bedrock } from 'langchain/llms/bedrock' +import { BaseBedrockInput } from 'langchain/dist/util/bedrock' + +/** + * I had to run the following to build the component + * and get the icon copied over to the dist directory + * Flowise/packages/components > yarn build + * + * @author Michael Connor + */ +class AWSBedrock_LLMs implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'AWS Bedrock' + this.name = 'awsBedrock' + this.version = 1.2 + this.type = 'AWSBedrock' + this.icon = 'awsBedrock.png' + this.category = 'LLMs' + this.description = 'Wrapper around AWS Bedrock large language models' + this.baseClasses = [this.type, ...getBaseClasses(Bedrock)] + this.credential = { + label: 'AWS Credential', + name: 'credential', + type: 'credential', + credentialNames: ['awsApi'], + optional: true + } + this.inputs = [ + { + label: 'Region', + name: 'region', + type: 'options', + options: [ + { label: 'af-south-1', name: 'af-south-1' }, + { label: 'ap-east-1', name: 'ap-east-1' }, + { label: 'ap-northeast-1', name: 'ap-northeast-1' }, + { label: 'ap-northeast-2', name: 'ap-northeast-2' }, + { label: 'ap-northeast-3', name: 'ap-northeast-3' }, + { label: 'ap-south-1', name: 'ap-south-1' }, + { label: 'ap-south-2', name: 'ap-south-2' }, + { label: 'ap-southeast-1', name: 'ap-southeast-1' }, + { label: 'ap-southeast-2', name: 'ap-southeast-2' }, + { label: 'ap-southeast-3', name: 'ap-southeast-3' }, + { label: 'ap-southeast-4', name: 'ap-southeast-4' }, + { label: 'ap-southeast-5', name: 'ap-southeast-5' }, + { label: 'ap-southeast-6', name: 'ap-southeast-6' }, + { label: 'ca-central-1', name: 'ca-central-1' }, + { label: 'ca-west-1', name: 'ca-west-1' }, + { label: 'cn-north-1', name: 'cn-north-1' }, + { label: 'cn-northwest-1', name: 'cn-northwest-1' }, + { label: 'eu-central-1', name: 'eu-central-1' }, + { label: 'eu-central-2', name: 'eu-central-2' }, + { label: 'eu-north-1', name: 'eu-north-1' }, + { label: 'eu-south-1', name: 'eu-south-1' }, + { label: 'eu-south-2', name: 'eu-south-2' }, + { label: 'eu-west-1', name: 'eu-west-1' }, + { label: 'eu-west-2', name: 'eu-west-2' }, + { label: 'eu-west-3', name: 'eu-west-3' }, + { label: 'il-central-1', name: 'il-central-1' }, + { label: 'me-central-1', name: 'me-central-1' }, + { label: 'me-south-1', name: 'me-south-1' }, + { label: 'sa-east-1', name: 'sa-east-1' }, + { label: 'us-east-1', name: 'us-east-1' }, + { label: 'us-east-2', name: 'us-east-2' }, + { label: 'us-gov-east-1', name: 'us-gov-east-1' }, + { label: 'us-gov-west-1', name: 'us-gov-west-1' }, + { label: 'us-west-1', name: 'us-west-1' }, + { label: 'us-west-2', name: 'us-west-2' } + ], + default: 'us-east-1', + optional: false + }, + { + label: 'Model Name', + name: 'model', + type: 'options', + options: [ + { label: 'amazon.titan-tg1-large', name: 'amazon.titan-tg1-large' }, + { label: 'amazon.titan-e1t-medium', name: 'amazon.titan-e1t-medium' }, + { label: 'stability.stable-diffusion-xl', name: 'stability.stable-diffusion-xl' }, + { label: 'ai21.j2-grande-instruct', name: 'ai21.j2-grande-instruct' }, + { label: 'ai21.j2-jumbo-instruct', name: 'ai21.j2-jumbo-instruct' }, + { label: 'ai21.j2-mid', name: 'ai21.j2-mid' }, + { label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' }, + { label: 'anthropic.claude-instant-v1', name: 'anthropic.claude-instant-v1' }, + { label: 'anthropic.claude-v1', name: 'anthropic.claude-v1' }, + { label: 'anthropic.claude-v2', name: 'anthropic.claude-v2' } + ], + default: 'anthropic.claude-v2', + optional: false + }, + { + label: 'Temperature', + name: 'temperature', + type: 'number', + step: 0.1, + description: 'Temperature parameter may not apply to certain model. Please check available model parameters', + optional: true, + default: 0.7, + additionalParams: false + }, + { + label: 'Max Tokens to Sample', + name: 'max_tokens_to_sample', + type: 'number', + step: 10, + description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters', + optional: false, + default: 200, + additionalParams: false + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const iRegion = nodeData.inputs?.region as string + const iModel = nodeData.inputs?.model as string + const iTemperature = nodeData.inputs?.temperature as string + const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string + + const obj: Partial = { + model: iModel, + region: iRegion, + temperature: parseFloat(iTemperature), + maxTokens: parseInt(iMax_tokens_to_sample, 10) + } + + /** + * Long-term credentials specified in LLM configuration are optional. + * Bedrock's credential provider falls back to the AWS SDK to fetch + * credentials from the running environment. + * When specified, we override the default provider with configured values. + * @see https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-provider-node/README.md + */ + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + if (credentialData && Object.keys(credentialData).length !== 0) { + const credentialApiKey = getCredentialParam('awsKey', credentialData, nodeData) + const credentialApiSecret = getCredentialParam('awsSecret', credentialData, nodeData) + const credentialApiSession = getCredentialParam('awsSession', credentialData, nodeData) + + obj.credentials = { + accessKeyId: credentialApiKey, + secretAccessKey: credentialApiSecret, + sessionToken: credentialApiSession + } + } + + const amazonBedrock = new Bedrock(obj) + return amazonBedrock + } +} + +module.exports = { nodeClass: AWSBedrock_LLMs } diff --git a/packages/components/nodes/llms/AWSBedrock/awsBedrock.png b/packages/components/nodes/llms/AWSBedrock/awsBedrock.png new file mode 100644 index 0000000000000000000000000000000000000000..483bc69a9c7ae460dba316682d08101557629b66 GIT binary patch literal 62897 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 literal 0 HcmV?d00001 From 5134fb3aed667c48938f0286832515bcdbe1168d Mon Sep 17 00:00:00 2001 From: Brian Krygsman Date: Mon, 2 Oct 2023 08:45:33 -0400 Subject: [PATCH 16/55] Add AWS Bedrock chat model support --- .../chatmodels/AWSBedrock/AWSChatBedrock.ts | 166 ++++++++++++++++++ .../chatmodels/AWSBedrock/awsBedrock.png | Bin 0 -> 62897 bytes 2 files changed, 166 insertions(+) create mode 100644 packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts create mode 100644 packages/components/nodes/chatmodels/AWSBedrock/awsBedrock.png diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts new file mode 100644 index 00000000..f5fa8bba --- /dev/null +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -0,0 +1,166 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { ChatBedrock } from 'langchain/chat_models/bedrock' +import { BaseBedrockInput } from 'langchain/dist/util/bedrock' + +/** + * I had to run the following to build the component + * and get the icon copied over to the dist directory + * Flowise/packages/components > yarn build + * + * @author Michael Connor + */ +class AWSChatBedrock_ChatModels implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'AWS Bedrock' + this.name = 'awsChatBedrock' + this.version = 1.1 + this.type = 'AWSChatBedrock' + this.icon = 'awsBedrock.png' + this.category = 'Chat Models' + this.description = 'Wrapper around AWS Bedrock large language models' + this.baseClasses = [this.type, ...getBaseClasses(ChatBedrock)] + this.credential = { + label: 'AWS Credential', + name: 'credential', + type: 'credential', + credentialNames: ['awsApi'], + optional: true + } + this.inputs = [ + { + label: 'Region', + name: 'region', + type: 'options', + options: [ + { label: 'af-south-1', name: 'af-south-1' }, + { label: 'ap-east-1', name: 'ap-east-1' }, + { label: 'ap-northeast-1', name: 'ap-northeast-1' }, + { label: 'ap-northeast-2', name: 'ap-northeast-2' }, + { label: 'ap-northeast-3', name: 'ap-northeast-3' }, + { label: 'ap-south-1', name: 'ap-south-1' }, + { label: 'ap-south-2', name: 'ap-south-2' }, + { label: 'ap-southeast-1', name: 'ap-southeast-1' }, + { label: 'ap-southeast-2', name: 'ap-southeast-2' }, + { label: 'ap-southeast-3', name: 'ap-southeast-3' }, + { label: 'ap-southeast-4', name: 'ap-southeast-4' }, + { label: 'ap-southeast-5', name: 'ap-southeast-5' }, + { label: 'ap-southeast-6', name: 'ap-southeast-6' }, + { label: 'ca-central-1', name: 'ca-central-1' }, + { label: 'ca-west-1', name: 'ca-west-1' }, + { label: 'cn-north-1', name: 'cn-north-1' }, + { label: 'cn-northwest-1', name: 'cn-northwest-1' }, + { label: 'eu-central-1', name: 'eu-central-1' }, + { label: 'eu-central-2', name: 'eu-central-2' }, + { label: 'eu-north-1', name: 'eu-north-1' }, + { label: 'eu-south-1', name: 'eu-south-1' }, + { label: 'eu-south-2', name: 'eu-south-2' }, + { label: 'eu-west-1', name: 'eu-west-1' }, + { label: 'eu-west-2', name: 'eu-west-2' }, + { label: 'eu-west-3', name: 'eu-west-3' }, + { label: 'il-central-1', name: 'il-central-1' }, + { label: 'me-central-1', name: 'me-central-1' }, + { label: 'me-south-1', name: 'me-south-1' }, + { label: 'sa-east-1', name: 'sa-east-1' }, + { label: 'us-east-1', name: 'us-east-1' }, + { label: 'us-east-2', name: 'us-east-2' }, + { label: 'us-gov-east-1', name: 'us-gov-east-1' }, + { label: 'us-gov-west-1', name: 'us-gov-west-1' }, + { label: 'us-west-1', name: 'us-west-1' }, + { label: 'us-west-2', name: 'us-west-2' } + ], + default: 'us-east-1', + optional: false + }, + { + label: 'Model Name', + name: 'model', + type: 'options', + options: [ + { label: 'amazon.titan-tg1-large', name: 'amazon.titan-tg1-large' }, + { label: 'amazon.titan-e1t-medium', name: 'amazon.titan-e1t-medium' }, + { label: 'stability.stable-diffusion-xl', name: 'stability.stable-diffusion-xl' }, + { label: 'ai21.j2-grande-instruct', name: 'ai21.j2-grande-instruct' }, + { label: 'ai21.j2-jumbo-instruct', name: 'ai21.j2-jumbo-instruct' }, + { label: 'ai21.j2-mid', name: 'ai21.j2-mid' }, + { label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' }, + { label: 'anthropic.claude-instant-v1', name: 'anthropic.claude-instant-v1' }, + { label: 'anthropic.claude-v1', name: 'anthropic.claude-v1' }, + { label: 'anthropic.claude-v2', name: 'anthropic.claude-v2' } + ], + default: 'anthropic.claude-v2', + optional: false + }, + { + label: 'Temperature', + name: 'temperature', + type: 'number', + step: 0.1, + description: 'Temperature parameter may not apply to certain model. Please check available model parameters', + optional: true, + default: 0.7, + additionalParams: false + }, + { + label: 'Max Tokens to Sample', + name: 'max_tokens_to_sample', + type: 'number', + step: 10, + description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters', + optional: false, + default: 200, + additionalParams: false + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const iRegion = nodeData.inputs?.region as string + const iModel = nodeData.inputs?.model as string + const iTemperature = nodeData.inputs?.temperature as string + const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string + + const obj: BaseBedrockInput = { + region: iRegion, + model: iModel, + maxTokens: parseInt(iMax_tokens_to_sample, 10), + temperature: parseFloat(iTemperature) + } + + /** + * Long-term credentials specified in LLM configuration are optional. + * Bedrock's credential provider falls back to the AWS SDK to fetch + * credentials from the running environment. + * When specified, we override the default provider with configured values. + * @see https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-provider-node/README.md + */ + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + if (credentialData && Object.keys(credentialData).length !== 0) { + const credentialApiKey = getCredentialParam('awsKey', credentialData, nodeData) + const credentialApiSecret = getCredentialParam('awsSecret', credentialData, nodeData) + const credentialApiSession = getCredentialParam('awsSession', credentialData, nodeData) + + obj.credentials = { + accessKeyId: credentialApiKey, + secretAccessKey: credentialApiSecret, + sessionToken: credentialApiSession + } + } + + const amazonBedrock = new ChatBedrock(obj) + return amazonBedrock + } +} + +module.exports = { nodeClass: AWSChatBedrock_ChatModels } diff --git a/packages/components/nodes/chatmodels/AWSBedrock/awsBedrock.png b/packages/components/nodes/chatmodels/AWSBedrock/awsBedrock.png new file mode 100644 index 0000000000000000000000000000000000000000..483bc69a9c7ae460dba316682d08101557629b66 GIT binary patch literal 62897 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 literal 0 HcmV?d00001 From 786dd8a11c3af6bb6cd122637d44978df600073b Mon Sep 17 00:00:00 2001 From: Ayush Jain Date: Wed, 4 Oct 2023 00:16:12 +0530 Subject: [PATCH 17/55] Added Upstash Redis Memory support --- .../UpstashRedisBackedChatMemory.ts | 131 ++++++++++++++++++ .../UpstashRedisBackedChatMemory/upstash.svg | 12 ++ packages/components/package.json | 3 +- 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts create mode 100644 packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts new file mode 100644 index 00000000..e0b5e20e --- /dev/null +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -0,0 +1,131 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import { ICommonObject } from '../../../src' +import { BufferMemory, BufferMemoryInput } from 'langchain/memory' +import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis"; +import { Redis, RedisConfigNodejs } from '@upstash/redis'; + +class UpstashRedisBackedChatMemory_Memory implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Upstash Redis-Backed Chat Memory' + this.name = 'UpstashRedisBackedChatMemory' + this.version = 1.0 + this.type = 'UpstashRedisBackedChatMemory' + this.icon = 'upstash.svg' + this.category = 'Memory' + this.description = 'Summarizes the conversation and stores the memory in upstash Redis server' + this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] + this.inputs = [ + { + label: 'Base URL', + name: 'baseURL', + type: 'string', + default: 'redis://localhost:6379' + }, + { + label: 'Token', + name: 'token', + type: 'string', + default: '********' + }, + { + label: 'Session Id', + name: 'sessionId', + type: 'string', + description: 'If not specified, the first CHAT_MESSAGE_ID will be used as sessionId', + default: '', + additionalParams: true, + optional: true + }, + { + label: 'Session Timeouts', + name: 'sessionTTL', + type: 'number', + description: 'Omit this parameter to make sessions never expire', + additionalParams: true, + optional: true + }, + { + label: 'Memory Key', + name: 'memoryKey', + type: 'string', + default: 'chat_history', + additionalParams: true + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + return initalizeUpstashRedis(nodeData, options) + } + + async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise { + const redis = initalizeUpstashRedis(nodeData, options) + const sessionId = nodeData.inputs?.sessionId as string + const chatId = options?.chatId as string + options.logger.info(`Clearing Upstash Redis memory session ${sessionId ? sessionId : chatId}`) + await redis.clear() + options.logger.info(`Successfully cleared Upstash Redis memory session ${sessionId ? sessionId : chatId}`) + } +} + +const initalizeUpstashRedis = (nodeData: INodeData, options: ICommonObject): BufferMemory => { + const baseURL = nodeData.inputs?.baseURL as string + const sessionId = nodeData.inputs?.sessionId as string + const sessionTTL = nodeData.inputs?.sessionTTL as number + const memoryKey = nodeData.inputs?.memoryKey as string + const chatId = options?.chatId as string + const token = nodeData.inputs?.token as string + + let isSessionIdUsingChatMessageId = false + if (!sessionId && chatId) isSessionIdUsingChatMessageId = true + + const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs; + const redisClient = new Redis(upstashRedisConfig) + let obj: UpstashRedisChatMessageHistoryInput = { + sessionId: sessionId ? sessionId : chatId, + client: redisClient + } + + if (sessionTTL) { + obj = { + ...obj, + sessionTTL + } + } + + const redisChatMessageHistory = new UpstashRedisChatMessageHistory(obj) + + const memory = new BufferMemoryExtended({ + memoryKey, + chatHistory: redisChatMessageHistory, + returnMessages: true, + isSessionIdUsingChatMessageId + }) + return memory +} + +interface BufferMemoryExtendedInput { + isSessionIdUsingChatMessageId: boolean +} + +class BufferMemoryExtended extends BufferMemory { + isSessionIdUsingChatMessageId? = false + + constructor(fields: BufferMemoryInput & Partial) { + super(fields) + this.isSessionIdUsingChatMessageId = fields.isSessionIdUsingChatMessageId + } +} + +module.exports = { nodeClass: UpstashRedisBackedChatMemory_Memory } diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg new file mode 100644 index 00000000..a0fb96a7 --- /dev/null +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg @@ -0,0 +1,12 @@ + + + upstash + + + + + + + + + diff --git a/packages/components/package.json b/packages/components/package.json index 93609106..77ada2ad 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -64,7 +64,8 @@ "srt-parser-2": "^1.2.3", "vm2": "^3.9.19", "weaviate-ts-client": "^1.1.0", - "ws": "^8.9.0" + "ws": "^8.9.0", + "@upstash/redis": "^1.22.1" }, "devDependencies": { "@types/gulp": "4.0.9", From 086944dc077752fb30eb8d887450af34ca398098 Mon Sep 17 00:00:00 2001 From: Ayush Jain Date: Thu, 5 Oct 2023 18:29:39 +0530 Subject: [PATCH 18/55] Fixed linting errors --- .../UpstashRedisBackedChatMemory.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index e0b5e20e..64b14e2c 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -2,8 +2,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { ICommonObject } from '../../../src' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis"; -import { Redis, RedisConfigNodejs } from '@upstash/redis'; +import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis" +import { Redis, RedisConfigNodejs } from '@upstash/redis' class UpstashRedisBackedChatMemory_Memory implements INode { label: string @@ -90,7 +90,7 @@ const initalizeUpstashRedis = (nodeData: INodeData, options: ICommonObject): Buf let isSessionIdUsingChatMessageId = false if (!sessionId && chatId) isSessionIdUsingChatMessageId = true - const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs; + const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs const redisClient = new Redis(upstashRedisConfig) let obj: UpstashRedisChatMessageHistoryInput = { sessionId: sessionId ? sessionId : chatId, From cddc68c187d6e430e1dce85497c8ff254caeb0a2 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 6 Oct 2023 13:17:56 +0530 Subject: [PATCH 19/55] LLM Cache - Addition of Upstash Redis --- .../credentials/UpstashRedisApi.credential.ts | 28 ++++++++ .../LLMUpstashRedisCache.ts | 66 ++++++++++++++++++ .../llmcache/LLMUpstashRedisCache/upstash.png | Bin 0 -> 2698 bytes packages/components/package.json | 3 +- 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 packages/components/credentials/UpstashRedisApi.credential.ts create mode 100644 packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts create mode 100644 packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png diff --git a/packages/components/credentials/UpstashRedisApi.credential.ts b/packages/components/credentials/UpstashRedisApi.credential.ts new file mode 100644 index 00000000..b6e62ff3 --- /dev/null +++ b/packages/components/credentials/UpstashRedisApi.credential.ts @@ -0,0 +1,28 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class UpstashRedisApi implements INodeCredential { + label: string + name: string + version: number + inputs: INodeParams[] + + constructor() { + this.label = 'Upstash Redis API' + this.name = 'upstashRedisApi' + this.version = 1.0 + this.inputs = [ + { + label: 'Upstash Redis REST URL', + name: 'upstashConnectionUrl', + type: 'string' + }, + { + label: 'Token', + name: 'upstashConnectionToken', + type: 'password' + } + ] + } +} + +module.exports = { credClass: UpstashRedisApi } diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts new file mode 100644 index 00000000..b16d6e13 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts @@ -0,0 +1,66 @@ +import { + getBaseClasses, + getCredentialData, + getCredentialParam, + ICommonObject, + INode, + INodeData, + INodeOutputsValue, + INodeParams +} from '../../../src' +import { UpstashRedisCache } from 'langchain/cache/upstash_redis' + +class LLMUpstashRedisCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + credential: INodeParams + + constructor() { + this.label = 'Upstash Redis LLM Cache' + this.name = 'upstashRedisCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'upstash.png' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['upstashRedisApi'] + } + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(UpstashRedisCache)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const upstashConnectionUrl = getCredentialParam('upstashConnectionUrl', credentialData, nodeData) + const upstashToken = getCredentialParam('upstashConnectionToken', credentialData, nodeData) + + const cache = new UpstashRedisCache({ + config: { + url: upstashConnectionUrl, + token: upstashToken + } + }) + return cache + } +} + +module.exports = { nodeClass: LLMUpstashRedisCache } diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png b/packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png new file mode 100644 index 0000000000000000000000000000000000000000..e27e02f4a3ba635cf04a33dbcfaa1a8e973ee2cc GIT binary patch literal 2698 zcmV;53U&2~P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf3Li;CK~z{rwODCv zRM#0jGhW6X+he@o1>0b-OTb{u1PC;ViGm<$NE4*0qHWrS0!gY?irP|KO4>->)$*rJ zgj#~s$`MLYnkFhK6bK=TB1l>j63k}sg24;M9`E+-i+jHN-psriKgT9Yj`cjA``)|v z+;2JGcWs#@@EM@fH-<}|K@0{xa0a{>341XX^1~YrBCJ1?3=1-oQjyJTPI4NGlkF%- zv7^>LSB=kvPfgYx4B+r+JKmq@MT>6)nbs7fTa%GwvGB6O%4aO{W6?g(&Pr)6NJuz|vhez7c6_}uPY_M696ge}Hrzy-9 zlreueq&y+yA8?dmYwl7MrrNa!h*^_8KGK1P!Di3^$f6a^2#S^D^2wr;L3sEX=65Tf zm1X27#hRo%kj71>^6zB&K)jJiLgsJ=-Kb8_!>)pr$S3I;$#(lE@bjM2aP#HtBpVlw zx0jHU*mQ>js7;%T($p+0;{ugw*_fA_sXrBiI}|{de;ijm!)Wu3qS-r$?tqK2o36Z+ zIDcR=gqz+md@XPBCzCzsY{tJv+f*_nCs;DF^HugjY;?@W{aGdYojZrP|L;Rr@!nWB z6ElE3t`{La5b&VFmW}7ZisO$ z+f8FAEwDMTBrO+}bnV)#dD=^}L>$>hS1*3q^FNd(SWVo%IeQVlnZHyYnTkg0?V+I- z^ia|y`)#}=&XdF^dKAe@l8}BTO^AO}BWQqPd@HX?$>2sZJvHpb`(iLS91 zVP~D6u%Dt7(6VG7K2s&)YEd3&0}Rr zL@TRLt9Jx8gX=@IXpryhE?$jld%iw8Jq|2-2(K=Gk_%B!xydM4$_KdNFI_prFf@!4 zimZptLr@FdD5Q?(vb>t1kCn?qHyTT$SanHyE^65B%@$kot8ldH8+5-%lZpr^n^&nW zPhUT-4`|Rl&+f#Mkg`HUB*+Z%s9Z6sf=OC>YGO#=@W|yuc%k=0eIy>6ax3vt#g}QZ zL4GsLm^KFuH{OMdMu|YNNwylrN`sJ@2>G-x32@L=(sW2NMIf=;>KQ?wxK+pN1I;Ko z`zLm6?f7BaVf?Q91N}}so+(;^n(T#|g^jT1VRQ3q`WKySX-Wpt7=NM)5v0B6QrLloakqm>+dOAja{sCOWDu!eYkwWFYw!<3_5LtGnSC*e5v3g|JbK1YyUZIQGy=a+s5& zMg%gR#YJB1Kaan%i=X1E1RP^y^4OJEIXkUwv?8T&E&GKv?28l8!Q=cpJSC{4jDU$~ zXJJ~aKOfg3M&Mz$w5{VU>aSHbDpu~+&M>)3N&1iTB5bTMPtC2t(*-NoOlPU{zf5y* z@Cwgu7w|C~6tKCDCrWQon#R`drl$HQo}wO#DIBn*xWwBVM1SZg*oiCUaxS7p1%lZ?p`M7kwzEDq95@&1L{XV^EGmt)JB z-)Qd}&vd?V)R*3mz2)oG*J;T{aFA8#NeVoqp-~z-O>!hcre$*kO50jTIZiEmLiMj^ z*vOE1d$?6A9udgqT~16s_yD#@&U>hNibN5NKo@$Z}b$F z`z8;4&$1`|Jn=C%`8ZwQ%|055|FvOxuX8NGd)4f96A&fa(BFh@SJ>gu!zFAwUgWO6 zl6RMS=(B>0WqBj5`2o8yMbemvLc>3bhq5bh!i1>6((iXo)-i#u@mv&jhr}K;F(bu} z?@*%tz--Jg>farrfwBG<_Op#F6kw>RcsD}goT^h_whnt)wx@$-d+U+OzjeOL!dx(Q z5|uEND0W{-T;vIs)^eWn*E{B;iV`HvhY`}>Ho5!p(fBRAKi-LREYVHsoFz)aXA?`Z z%ulyxQf1E7Y{%khDq93947z+{c(nPSxHv-jP&+q~7@0Uio+n$db<;W|Q3GCbPsoS| znC zg%Fg@G1DvPou8K0;i znH(~K9E0*%YRh=sDQ2cu+vcFq=D<3}dDSeA<}(BMKR;-3TtO!==>Px#07*qoM6N<$ Ef=GE79{>OV literal 0 HcmV?d00001 diff --git a/packages/components/package.json b/packages/components/package.json index 5e993f86..e3c4380a 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -29,6 +29,7 @@ "@supabase/supabase-js": "^2.29.0", "@types/js-yaml": "^4.0.5", "@types/jsdom": "^21.1.1", + "@upstash/redis": "^1.22.1", "@zilliz/milvus2-sdk-node": "^2.2.24", "apify-client": "^2.7.1", "axios": "^0.27.2", @@ -44,7 +45,7 @@ "graphql": "^16.6.0", "html-to-text": "^9.0.5", "ioredis": "^5.3.2", - "langchain": "^0.0.154", + "langchain": "^0.0.157", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", From b63b5f8a634ad373dc151d12dd8dad62c28ee12f Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 6 Oct 2023 17:03:48 +0100 Subject: [PATCH 20/55] remove vectara metadata check --- .../ui/src/views/chatmessage/ChatMessage.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/ui/src/views/chatmessage/ChatMessage.js b/packages/ui/src/views/chatmessage/ChatMessage.js index 7a15d9ff..3e967541 100644 --- a/packages/ui/src/views/chatmessage/ChatMessage.js +++ b/packages/ui/src/views/chatmessage/ChatMessage.js @@ -64,27 +64,10 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => { window.open(data, '_blank') } - const handleVectaraMetadata = (message) => { - if (message.sourceDocuments && message.sourceDocuments[0].metadata.length) - message.sourceDocuments = message.sourceDocuments.map((docs) => { - const newMetadata = docs.metadata.reduce((newMetadata, metadata) => { - newMetadata[metadata.name] = metadata.value - return newMetadata - }, {}) - return { - pageContent: docs.pageContent, - metadata: newMetadata - } - }) - return message - } - const removeDuplicateURL = (message) => { const visitedURLs = [] const newSourceDocuments = [] - message = handleVectaraMetadata(message) - message.sourceDocuments.forEach((source) => { if (isValidURL(source.metadata.source) && !visitedURLs.includes(source.metadata.source)) { visitedURLs.push(source.metadata.source) @@ -174,8 +157,6 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => { if (response.data) { let data = response.data - data = handleVectaraMetadata(data) - if (typeof data === 'object' && data.text && data.sourceDocuments) { if (!isChatFlowAvailableToStream) { setMessages((prevMessages) => [ From 14f2dcae6ada356d4b7aa732f81cf29ba81ab2e7 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 6 Oct 2023 17:06:00 +0100 Subject: [PATCH 21/55] add plain text doc loader --- .../documentloaders/PlainText/PlainText.ts | 88 +++++++++++++++++++ .../documentloaders/PlainText/plaintext.svg | 7 ++ 2 files changed, 95 insertions(+) create mode 100644 packages/components/nodes/documentloaders/PlainText/PlainText.ts create mode 100644 packages/components/nodes/documentloaders/PlainText/plaintext.svg diff --git a/packages/components/nodes/documentloaders/PlainText/PlainText.ts b/packages/components/nodes/documentloaders/PlainText/PlainText.ts new file mode 100644 index 00000000..261f2d98 --- /dev/null +++ b/packages/components/nodes/documentloaders/PlainText/PlainText.ts @@ -0,0 +1,88 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { TextSplitter } from 'langchain/text_splitter' +import { Document } from 'langchain/document' + +class PlainText_DocumentLoaders implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Plain Text' + this.name = 'plainText' + this.version = 1.0 + this.type = 'Document' + this.icon = 'plaintext.svg' + this.category = 'Document Loaders' + this.description = `Load data from plain text` + this.baseClasses = [this.type] + this.inputs = [ + { + label: 'Text', + name: 'text', + type: 'string', + rows: 4, + placeholder: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua...' + }, + { + label: 'Text Splitter', + name: 'textSplitter', + type: 'TextSplitter', + optional: true + }, + { + label: 'Metadata', + name: 'metadata', + type: 'json', + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const textSplitter = nodeData.inputs?.textSplitter as TextSplitter + const text = nodeData.inputs?.text as string + const metadata = nodeData.inputs?.metadata + + let alldocs: Document>[] = [] + + if (textSplitter) { + const docs = await textSplitter.createDocuments([text]) + alldocs.push(...docs) + } else { + alldocs.push( + new Document({ + pageContent: text + }) + ) + } + + if (metadata) { + const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) + let finaldocs: Document>[] = [] + for (const doc of alldocs) { + const newdoc = { + ...doc, + metadata: { + ...doc.metadata, + ...parsedMetadata + } + } + finaldocs.push(newdoc) + } + return finaldocs + } + + return alldocs + } +} + +module.exports = { nodeClass: PlainText_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/PlainText/plaintext.svg b/packages/components/nodes/documentloaders/PlainText/plaintext.svg new file mode 100644 index 00000000..b9fec035 --- /dev/null +++ b/packages/components/nodes/documentloaders/PlainText/plaintext.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From 1cb991a2d7c5be8785d768b028bb958054701afd Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 6 Oct 2023 18:43:41 +0100 Subject: [PATCH 22/55] add similarity threshold --- .../SimilarityThresholdRetriever.ts | 107 ++++++++++++++++++ .../similaritythreshold.svg | 5 + 2 files changed, 112 insertions(+) create mode 100644 packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts create mode 100644 packages/components/nodes/retrievers/SimilarityThresholdRetriever/similaritythreshold.svg diff --git a/packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts b/packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts new file mode 100644 index 00000000..a9f4b3d8 --- /dev/null +++ b/packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts @@ -0,0 +1,107 @@ +import { VectorStore } from 'langchain/vectorstores/base' +import { INode, INodeData, INodeParams, INodeOutputsValue } from '../../../src/Interface' +import { handleEscapeCharacters } from '../../../src' +import { ScoreThresholdRetriever } from 'langchain/retrievers/score_threshold' + +class SimilarityThresholdRetriever_Retrievers implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Similarity Score Threshold Retriever' + this.name = 'similarityThresholdRetriever' + this.version = 1.0 + this.type = 'SimilarityThresholdRetriever' + this.icon = 'similaritythreshold.svg' + this.category = 'Retrievers' + this.description = 'Return results based on the minimum similarity percentage' + this.baseClasses = [this.type, 'BaseRetriever'] + this.inputs = [ + { + label: 'Vector Store', + name: 'vectorStore', + type: 'VectorStore' + }, + { + label: 'Minimum Similarity Score (%)', + name: 'minSimilarityScore', + description: 'Finds results with at least this similarity score', + type: 'number', + default: 80, + step: 1 + }, + { + label: 'Max K', + name: 'maxK', + description: `The maximum number of results to fetch`, + type: 'number', + default: 20, + step: 1 + }, + { + label: 'K Increment', + name: 'kIncrement', + description: `How much to increase K by each time. It'll fetch N results, then N + kIncrement, then N + kIncrement * 2, etc.`, + type: 'number', + default: 2, + step: 1 + } + ] + this.outputs = [ + { + label: 'Similarity Threshold Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Document', + name: 'document', + baseClasses: ['Document'] + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] + } + + async init(nodeData: INodeData, input: string): Promise { + const vectorStore = nodeData.inputs?.vectorStore as VectorStore + const minSimilarityScore = nodeData.inputs?.minSimilarityScore as number + const maxK = nodeData.inputs?.maxK as string + const kIncrement = nodeData.inputs?.kIncrement as string + + const output = nodeData.outputs?.output as string + + const retriever = ScoreThresholdRetriever.fromVectorStore(vectorStore, { + minSimilarityScore: minSimilarityScore ? minSimilarityScore / 100 : 0.9, + maxK: maxK ? parseInt(maxK, 10) : 100, + kIncrement: kIncrement ? parseInt(kIncrement, 10) : 2 + }) + + if (output === 'retriever') return retriever + else if (output === 'document') return await retriever.getRelevantDocuments(input) + else if (output === 'text') { + let finaltext = '' + + const docs = await retriever.getRelevantDocuments(input) + + for (const doc of docs) finaltext += `${doc.pageContent}\n` + + return handleEscapeCharacters(finaltext, false) + } + + return retriever + } +} + +module.exports = { nodeClass: SimilarityThresholdRetriever_Retrievers } diff --git a/packages/components/nodes/retrievers/SimilarityThresholdRetriever/similaritythreshold.svg b/packages/components/nodes/retrievers/SimilarityThresholdRetriever/similaritythreshold.svg new file mode 100644 index 00000000..6b918fd8 --- /dev/null +++ b/packages/components/nodes/retrievers/SimilarityThresholdRetriever/similaritythreshold.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 9bae1c33f71070fe8406a78ad1b4a343402b3b33 Mon Sep 17 00:00:00 2001 From: Ayush Jain Date: Fri, 6 Oct 2023 23:23:21 +0530 Subject: [PATCH 23/55] Review changes --- .../UpstashRedisMemoryApi.credential.ts | 26 ++++++++++++++++ .../UpstashRedisBackedChatMemory.ts | 30 +++++++++++-------- 2 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 packages/components/credentials/UpstashRedisMemoryApi.credential.ts diff --git a/packages/components/credentials/UpstashRedisMemoryApi.credential.ts b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts new file mode 100644 index 00000000..9c0f99aa --- /dev/null +++ b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts @@ -0,0 +1,26 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class UpstashRedisMemoryApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Upstash Redis Memory API' + this.name = 'upstashRedisMemoryApi' + this.version = 1.0 + this.description = + 'Refer to official guide on how to create redis instance and get password on upstash' + this.inputs = [ + { + label: 'Upstash Redis Password', + name: 'upstashRedisPassword', + type: 'password' + } + ] + } +} + +module.exports = { credClass: UpstashRedisMemoryApi } diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 64b14e2c..98983ecb 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -1,8 +1,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' -import { getBaseClasses } from '../../../src/utils' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ICommonObject } from '../../../src' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis" +import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from 'langchain/stores/message/upstash_redis' import { Redis, RedisConfigNodejs } from '@upstash/redis' class UpstashRedisBackedChatMemory_Memory implements INode { @@ -14,6 +14,7 @@ class UpstashRedisBackedChatMemory_Memory implements INode { icon: string category: string baseClasses: string[] + credential: INodeParams inputs: INodeParams[] constructor() { @@ -25,18 +26,19 @@ class UpstashRedisBackedChatMemory_Memory implements INode { this.category = 'Memory' this.description = 'Summarizes the conversation and stores the memory in upstash Redis server' this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + description: 'Configure password authentication on your upstash redis instance', + credentialNames: ['upstashRedisMemoryApi'] + } this.inputs = [ { label: 'Base URL', name: 'baseURL', type: 'string', - default: 'redis://localhost:6379' - }, - { - label: 'Token', - name: 'token', - type: 'string', - default: '********' + default: 'https://.upstash.io' }, { label: 'Session Id', @@ -70,7 +72,7 @@ class UpstashRedisBackedChatMemory_Memory implements INode { } async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise { - const redis = initalizeUpstashRedis(nodeData, options) + const redis = await initalizeUpstashRedis(nodeData, options) const sessionId = nodeData.inputs?.sessionId as string const chatId = options?.chatId as string options.logger.info(`Clearing Upstash Redis memory session ${sessionId ? sessionId : chatId}`) @@ -79,18 +81,20 @@ class UpstashRedisBackedChatMemory_Memory implements INode { } } -const initalizeUpstashRedis = (nodeData: INodeData, options: ICommonObject): BufferMemory => { +const initalizeUpstashRedis = async (nodeData: INodeData, options: ICommonObject): Promise => { const baseURL = nodeData.inputs?.baseURL as string const sessionId = nodeData.inputs?.sessionId as string const sessionTTL = nodeData.inputs?.sessionTTL as number const memoryKey = nodeData.inputs?.memoryKey as string const chatId = options?.chatId as string - const token = nodeData.inputs?.token as string let isSessionIdUsingChatMessageId = false if (!sessionId && chatId) isSessionIdUsingChatMessageId = true - const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const upstashRedisPassword = getCredentialParam('upstashRedisPassword', credentialData, nodeData) + + const upstashRedisConfig = { url: baseURL, token: upstashRedisPassword } as RedisConfigNodejs const redisClient = new Redis(upstashRedisConfig) let obj: UpstashRedisChatMessageHistoryInput = { sessionId: sessionId ? sessionId : chatId, From 0b0cf357c58d8f88aaf22adc68abef41af607e80 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:34:07 +0100 Subject: [PATCH 24/55] Update LLMInMemoryCache.ts code cleanup --- .../llmcache/LLMInMemoryCache/LLMInMemoryCache.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts index 5e77a029..44133486 100644 --- a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts +++ b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts @@ -1,4 +1,4 @@ -import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { INode, INodeParams } from '../../../src/Interface' import { InMemoryCache } from 'langchain/cache' import { getBaseClasses } from '../../../src' @@ -12,7 +12,6 @@ class LLMInMemoryCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] inMemoryCache: any constructor() { @@ -22,18 +21,11 @@ class LLMInMemoryCache implements INode { this.type = 'LLMCache' this.icon = 'memorycache.png' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(InMemoryCache)] this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(InMemoryCache)] - } - ] } - async init(nodeData: INodeData): Promise { + async init(): Promise { if (!this.inMemoryCache) { this.inMemoryCache = InMemoryCache.global() } From 2785e3b685f6e5adcee00af3b52dcfec0f5af058 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:34:36 +0100 Subject: [PATCH 25/55] Update LLMMomentoCache.ts code cleanup --- .../LLMMomentoCache/LLMMomentoCache.ts | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts index 82267c24..f8fd61fb 100644 --- a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts +++ b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts @@ -1,13 +1,4 @@ -import { - getBaseClasses, - getCredentialData, - getCredentialParam, - ICommonObject, - INode, - INodeData, - INodeOutputsValue, - INodeParams -} from '../../../src' +import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { MomentoCache } from 'langchain/cache/momento' import { CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk' @@ -21,7 +12,6 @@ class LLMMomentoCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] credential: INodeParams constructor() { @@ -31,7 +21,7 @@ class LLMMomentoCache implements INode { this.type = 'LLMCache' this.icon = 'momento.png' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(MomentoCache)] this.credential = { label: 'Connect Credential', name: 'credential', @@ -40,13 +30,6 @@ class LLMMomentoCache implements INode { credentialNames: ['momentoCacheApi'] } this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(MomentoCache)] - } - ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { From 52ccb89949cb75a32730bdd7fcaeb00fe8195cf6 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:34:56 +0100 Subject: [PATCH 26/55] Update LLMRedisCache.ts code cleanup --- .../llmcache/LLMRedisCache/LLMRedisCache.ts | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts index 4a098e82..a7208977 100644 --- a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts +++ b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts @@ -1,13 +1,4 @@ -import { - getBaseClasses, - getCredentialData, - getCredentialParam, - ICommonObject, - INode, - INodeData, - INodeOutputsValue, - INodeParams -} from '../../../src' +import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { RedisCache } from 'langchain/cache/ioredis' import { Redis } from 'ioredis' @@ -21,7 +12,6 @@ class LLMRedisCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] credential: INodeParams constructor() { @@ -31,7 +21,7 @@ class LLMRedisCache implements INode { this.type = 'LLMCache' this.icon = 'redis.svg' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(RedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', @@ -40,13 +30,6 @@ class LLMRedisCache implements INode { credentialNames: ['redisCacheApi'] } this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(RedisCache)] - } - ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { @@ -55,18 +38,12 @@ class LLMRedisCache implements INode { const password = getCredentialParam('redisCachePwd', credentialData, nodeData) const portStr = getCredentialParam('redisCachePort', credentialData, nodeData) const host = getCredentialParam('redisCacheHost', credentialData, nodeData) - let port = 6379 - try { - port = portStr ? parseInt(portStr) : 6379 - } catch (e) { - port = 6379 - } const client = new Redis({ - port: port, // Redis port - host: host, - username: username, - password: password + port: portStr ? parseInt(portStr) : 6379, + host, + username, + password }) return new RedisCache(client) } From 5288ea8155447fb75b843eec05deb540231d249d Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:35:16 +0100 Subject: [PATCH 27/55] Update LLMUpstashRedisCache.ts code cleanup --- .../LLMUpstashRedisCache.ts | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts index b16d6e13..8914b2a1 100644 --- a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts +++ b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts @@ -1,13 +1,4 @@ -import { - getBaseClasses, - getCredentialData, - getCredentialParam, - ICommonObject, - INode, - INodeData, - INodeOutputsValue, - INodeParams -} from '../../../src' +import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { UpstashRedisCache } from 'langchain/cache/upstash_redis' class LLMUpstashRedisCache implements INode { @@ -20,7 +11,6 @@ class LLMUpstashRedisCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] credential: INodeParams constructor() { @@ -30,7 +20,7 @@ class LLMUpstashRedisCache implements INode { this.type = 'LLMCache' this.icon = 'upstash.png' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(UpstashRedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', @@ -39,13 +29,6 @@ class LLMUpstashRedisCache implements INode { credentialNames: ['upstashRedisApi'] } this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(UpstashRedisCache)] - } - ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { From 8ee4f0fc3c71971d7408c65d91d9b9f3f7735c46 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:36:09 +0100 Subject: [PATCH 28/55] Update Interface.ts code cleanup --- packages/components/src/Interface.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index 76dc7354..e883d056 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -1,7 +1,6 @@ /** * Types */ -import { BaseCache } from 'langchain/schema' export type NodeParamsType = | 'asyncOptions' @@ -177,9 +176,3 @@ export class VectorStoreRetriever { this.vectorStore = fields.vectorStore } } - -export interface LLMCacheBase { - name: string - description: string - baseCache: BaseCache -} From dbd655580d9bf68c7976b0b4502426ad8774ff3c Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sat, 7 Oct 2023 19:17:33 +0100 Subject: [PATCH 29/55] Add fix where flow is not restarted when cache is used --- packages/server/src/utils/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index bb048490..98802cde 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -477,6 +477,7 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: */ export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[], nodes: IReactFlowNode[]): boolean => { for (const node of startingNodes) { + if (node.data.category === 'LLM Cache') return true for (const inputName in node.data.inputs) { const inputVariables = getInputVariables(node.data.inputs[inputName]) if (inputVariables.length > 0) return true From 424e71312873fc88023fb7bc3e91bcb607f4a06b Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:52:19 +0100 Subject: [PATCH 30/55] Update UpstashRedisBackedChatMemory.ts code cleanup --- .../UpstashRedisBackedChatMemory.ts | 41 ++++++------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 98983ecb..00d7697a 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -2,8 +2,7 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ICommonObject } from '../../../src' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from 'langchain/stores/message/upstash_redis' -import { Redis, RedisConfigNodejs } from '@upstash/redis' +import { UpstashRedisChatMessageHistory } from 'langchain/stores/message/upstash_redis' class UpstashRedisBackedChatMemory_Memory implements INode { label: string @@ -35,10 +34,10 @@ class UpstashRedisBackedChatMemory_Memory implements INode { } this.inputs = [ { - label: 'Base URL', + label: 'Upstash Redis REST URL', name: 'baseURL', type: 'string', - default: 'https://.upstash.io' + placeholder: 'https://.upstash.io' }, { label: 'Session Id', @@ -56,13 +55,6 @@ class UpstashRedisBackedChatMemory_Memory implements INode { description: 'Omit this parameter to make sessions never expire', additionalParams: true, optional: true - }, - { - label: 'Memory Key', - name: 'memoryKey', - type: 'string', - default: 'chat_history', - additionalParams: true } ] } @@ -84,38 +76,29 @@ class UpstashRedisBackedChatMemory_Memory implements INode { const initalizeUpstashRedis = async (nodeData: INodeData, options: ICommonObject): Promise => { const baseURL = nodeData.inputs?.baseURL as string const sessionId = nodeData.inputs?.sessionId as string - const sessionTTL = nodeData.inputs?.sessionTTL as number - const memoryKey = nodeData.inputs?.memoryKey as string + const sessionTTL = nodeData.inputs?.sessionTTL as string const chatId = options?.chatId as string let isSessionIdUsingChatMessageId = false if (!sessionId && chatId) isSessionIdUsingChatMessageId = true const credentialData = await getCredentialData(nodeData.credential ?? '', options) - const upstashRedisPassword = getCredentialParam('upstashRedisPassword', credentialData, nodeData) + const upstashRestToken = getCredentialParam('upstashRestToken', credentialData, nodeData) - const upstashRedisConfig = { url: baseURL, token: upstashRedisPassword } as RedisConfigNodejs - const redisClient = new Redis(upstashRedisConfig) - let obj: UpstashRedisChatMessageHistoryInput = { + const redisChatMessageHistory = new UpstashRedisChatMessageHistory({ sessionId: sessionId ? sessionId : chatId, - client: redisClient - } - - if (sessionTTL) { - obj = { - ...obj, - sessionTTL + sessionTTL: sessionTTL ? parseInt(sessionTTL, 10) : undefined, + config: { + url: baseURL, + token: upstashRestToken } - } - - const redisChatMessageHistory = new UpstashRedisChatMessageHistory(obj) + }) const memory = new BufferMemoryExtended({ - memoryKey, chatHistory: redisChatMessageHistory, - returnMessages: true, isSessionIdUsingChatMessageId }) + return memory } From e2355555ed16e87be60d697378f9485e031d22ec Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:52:48 +0100 Subject: [PATCH 31/55] Update UpstashRedisMemoryApi.credential.ts rename token label --- .../credentials/UpstashRedisMemoryApi.credential.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/credentials/UpstashRedisMemoryApi.credential.ts b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts index 9c0f99aa..8d3e9528 100644 --- a/packages/components/credentials/UpstashRedisMemoryApi.credential.ts +++ b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts @@ -12,11 +12,11 @@ class UpstashRedisMemoryApi implements INodeCredential { this.name = 'upstashRedisMemoryApi' this.version = 1.0 this.description = - 'Refer to official guide on how to create redis instance and get password on upstash' + 'Refer to official guide on how to create redis instance and get redis REST Token' this.inputs = [ { - label: 'Upstash Redis Password', - name: 'upstashRedisPassword', + label: 'Upstash Redis REST Token', + name: 'upstashRestToken', type: 'password' } ] From 7c020c4b3ea97c8fef4b79e4d3a083d1bca7cf9f Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:53:58 +0100 Subject: [PATCH 32/55] Update package.json --- packages/components/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/package.json b/packages/components/package.json index 77ada2ad..cf5a5f17 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -28,6 +28,7 @@ "@supabase/supabase-js": "^2.29.0", "@types/js-yaml": "^4.0.5", "@types/jsdom": "^21.1.1", + "@upstash/redis": "^1.22.1", "@zilliz/milvus2-sdk-node": "^2.2.24", "apify-client": "^2.7.1", "axios": "^0.27.2", @@ -64,8 +65,7 @@ "srt-parser-2": "^1.2.3", "vm2": "^3.9.19", "weaviate-ts-client": "^1.1.0", - "ws": "^8.9.0", - "@upstash/redis": "^1.22.1" + "ws": "^8.9.0" }, "devDependencies": { "@types/gulp": "4.0.9", From 8b555e02f80b7deedb8d54f658a390e8e431feaf Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:55:45 +0100 Subject: [PATCH 33/55] Update UpstashRedisBackedChatMemory.ts camelCase node name --- .../UpstashRedisBackedChatMemory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 00d7697a..6b5fdf66 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -18,12 +18,12 @@ class UpstashRedisBackedChatMemory_Memory implements INode { constructor() { this.label = 'Upstash Redis-Backed Chat Memory' - this.name = 'UpstashRedisBackedChatMemory' + this.name = 'upstashRedisBackedChatMemory' this.version = 1.0 this.type = 'UpstashRedisBackedChatMemory' this.icon = 'upstash.svg' this.category = 'Memory' - this.description = 'Summarizes the conversation and stores the memory in upstash Redis server' + this.description = 'Summarizes the conversation and stores the memory in Upstash Redis server' this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] this.credential = { label: 'Connect Credential', From 679eac1d0b24c5b7b8ba6a582dcf88ebc4589588 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 11:44:43 +0530 Subject: [PATCH 34/55] Addition of Cache Option for Chat Models --- .../nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts | 14 ++++++++++++-- .../chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts | 14 ++++++++++++-- .../nodes/chatmodels/Bittensor/Bittensor.ts | 13 ++++++++++++- .../chatmodels/ChatAnthropic/ChatAnthropic.ts | 14 ++++++++++++-- .../chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts | 11 ++++++++++- .../ChatGoogleVertexAI/ChatGoogleVertexAI.ts | 11 ++++++++++- .../chatmodels/ChatHuggingFace/ChatHuggingFace.ts | 11 ++++++++++- .../nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts | 14 ++++++++++++-- .../nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts | 15 +++++++++++++-- .../ChatOpenAICustom/ChatOpenAICustom.ts | 14 ++++++++++++-- 10 files changed, 115 insertions(+), 16 deletions(-) diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts index f5fa8bba..ba4bdd8a 100644 --- a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -2,6 +2,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatBedrock } from 'langchain/chat_models/bedrock' import { BaseBedrockInput } from 'langchain/dist/util/bedrock' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' /** * I had to run the following to build the component @@ -25,7 +27,7 @@ class AWSChatBedrock_ChatModels implements INode { constructor() { this.label = 'AWS Bedrock' this.name = 'awsChatBedrock' - this.version = 1.1 + this.version = 2.0 this.type = 'AWSChatBedrock' this.icon = 'awsBedrock.png' this.category = 'Chat Models' @@ -39,6 +41,12 @@ class AWSChatBedrock_ChatModels implements INode { optional: true } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Region', name: 'region', @@ -130,8 +138,9 @@ class AWSChatBedrock_ChatModels implements INode { const iModel = nodeData.inputs?.model as string const iTemperature = nodeData.inputs?.temperature as string const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string + const cache = nodeData.inputs?.llmCache as BaseCache - const obj: BaseBedrockInput = { + const obj: BaseBedrockInput & BaseLLMParams = { region: iRegion, model: iModel, maxTokens: parseInt(iMax_tokens_to_sample, 10), @@ -157,6 +166,7 @@ class AWSChatBedrock_ChatModels implements INode { sessionToken: credentialApiSession } } + if (cache) obj.cache = cache const amazonBedrock = new ChatBedrock(obj) return amazonBedrock diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index 90f430f0..5acf4dce 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -2,6 +2,8 @@ import { OpenAIBaseInput } from 'langchain/dist/types/openai-types' import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { AzureOpenAIInput, ChatOpenAI } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class AzureChatOpenAI_ChatModels implements INode { label: string @@ -18,7 +20,7 @@ class AzureChatOpenAI_ChatModels implements INode { constructor() { this.label = 'Azure ChatOpenAI' this.name = 'azureChatOpenAI' - this.version = 1.0 + this.version = 2.0 this.type = 'AzureChatOpenAI' this.icon = 'Azure.svg' this.category = 'Chat Models' @@ -31,6 +33,12 @@ class AzureChatOpenAI_ChatModels implements INode { credentialNames: ['azureOpenAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -107,6 +115,7 @@ class AzureChatOpenAI_ChatModels implements INode { const presencePenalty = nodeData.inputs?.presencePenalty as string const timeout = nodeData.inputs?.timeout as string const streaming = nodeData.inputs?.streaming as boolean + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const azureOpenAIApiKey = getCredentialParam('azureOpenAIApiKey', credentialData, nodeData) @@ -114,7 +123,7 @@ class AzureChatOpenAI_ChatModels implements INode { const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData) const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData) - const obj: Partial & Partial = { + const obj: Partial & BaseLLMParams & Partial = { temperature: parseFloat(temperature), modelName, azureOpenAIApiKey, @@ -128,6 +137,7 @@ class AzureChatOpenAI_ChatModels implements INode { if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty) if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache const model = new ChatOpenAI(obj) return model diff --git a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts index cfcac863..89c37157 100644 --- a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts +++ b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts @@ -1,6 +1,7 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { NIBittensorChatModel, BittensorInput } from 'langchain/experimental/chat_models/bittensor' +import { BaseCache } from 'langchain/schema' class Bittensor_ChatModels implements INode { label: string @@ -16,13 +17,19 @@ class Bittensor_ChatModels implements INode { constructor() { this.label = 'NIBittensorChat' this.name = 'NIBittensorChatModel' - this.version = 1.0 + this.version = 2.0 this.type = 'BittensorChat' this.icon = 'logo.png' this.category = 'Chat Models' this.description = 'Wrapper around Bittensor subnet 1 large language models' this.baseClasses = [this.type, ...getBaseClasses(NIBittensorChatModel)] this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'System prompt', name: 'system_prompt', @@ -35,9 +42,13 @@ class Bittensor_ChatModels implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string + const cache = nodeData.inputs?.llmCache as BaseCache + const obj: Partial = { systemPrompt: system_prompt } + if (cache) obj.cache = cache + const model = new NIBittensorChatModel(obj) return model } diff --git a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts index 12a33d99..039b437b 100644 --- a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts +++ b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { AnthropicInput, ChatAnthropic } from 'langchain/chat_models/anthropic' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatAnthropic_ChatModels implements INode { label: string @@ -17,7 +19,7 @@ class ChatAnthropic_ChatModels implements INode { constructor() { this.label = 'ChatAnthropic' this.name = 'chatAnthropic' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatAnthropic' this.icon = 'chatAnthropic.png' this.category = 'Chat Models' @@ -30,6 +32,12 @@ class ChatAnthropic_ChatModels implements INode { credentialNames: ['anthropicApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -135,11 +143,12 @@ class ChatAnthropic_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const streaming = nodeData.inputs?.streaming as boolean + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const anthropicApiKey = getCredentialParam('anthropicApiKey', credentialData, nodeData) - const obj: Partial & { anthropicApiKey?: string } = { + const obj: Partial & BaseLLMParams & { anthropicApiKey?: string } = { temperature: parseFloat(temperature), modelName, anthropicApiKey, @@ -149,6 +158,7 @@ class ChatAnthropic_ChatModels implements INode { if (maxTokensToSample) obj.maxTokensToSample = parseInt(maxTokensToSample, 10) if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) + if (cache) obj.cache = cache const model = new ChatAnthropic(obj) return model diff --git a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts index 642ddb5e..8ee3fbb8 100644 --- a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts +++ b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatGooglePaLM, GooglePaLMChatInput } from 'langchain/chat_models/googlepalm' +import { BaseCache } from 'langchain/schema' class ChatGooglePaLM_ChatModels implements INode { label: string @@ -17,7 +18,7 @@ class ChatGooglePaLM_ChatModels implements INode { constructor() { this.label = 'ChatGooglePaLM' this.name = 'chatGooglePaLM' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatGooglePaLM' this.icon = 'Google_PaLM_Logo.svg' this.category = 'Chat Models' @@ -30,6 +31,12 @@ class ChatGooglePaLM_ChatModels implements INode { credentialNames: ['googleMakerSuite'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -96,6 +103,7 @@ class ChatGooglePaLM_ChatModels implements INode { const temperature = nodeData.inputs?.temperature as string const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) @@ -108,6 +116,7 @@ class ChatGooglePaLM_ChatModels implements INode { if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) + if (cache) obj.cache = cache const model = new ChatGooglePaLM(obj) return model diff --git a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts index 4cb206f5..4f876239 100644 --- a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts +++ b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts @@ -2,6 +2,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatGoogleVertexAI, GoogleVertexAIChatInput } from 'langchain/chat_models/googlevertexai' import { GoogleAuthOptions } from 'google-auth-library' +import { BaseCache } from 'langchain/schema' class GoogleVertexAI_ChatModels implements INode { label: string @@ -18,7 +19,7 @@ class GoogleVertexAI_ChatModels implements INode { constructor() { this.label = 'ChatGoogleVertexAI' this.name = 'chatGoogleVertexAI' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatGoogleVertexAI' this.icon = 'vertexai.svg' this.category = 'Chat Models' @@ -34,6 +35,12 @@ class GoogleVertexAI_ChatModels implements INode { 'Google Vertex AI credential. If you are using a GCP service like Cloud Run, or if you have installed default credentials on your local machine, you do not need to set this credential.' } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -113,6 +120,7 @@ class GoogleVertexAI_ChatModels implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string + const cache = nodeData.inputs?.llmCache as BaseCache const obj: GoogleVertexAIChatInput = { temperature: parseFloat(temperature), @@ -122,6 +130,7 @@ class GoogleVertexAI_ChatModels implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) + if (cache) obj.cache = cache const model = new ChatGoogleVertexAI(obj) return model diff --git a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts index ee55c7bb..d9c0d22f 100644 --- a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts +++ b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { HFInput, HuggingFaceInference } from './core' +import { BaseCache } from 'langchain/schema' class ChatHuggingFace_ChatModels implements INode { label: string @@ -17,7 +18,7 @@ class ChatHuggingFace_ChatModels implements INode { constructor() { this.label = 'ChatHuggingFace' this.name = 'chatHuggingFace' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatHuggingFace' this.icon = 'huggingface.png' this.category = 'Chat Models' @@ -30,6 +31,12 @@ class ChatHuggingFace_ChatModels implements INode { credentialNames: ['huggingFaceApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model', name: 'model', @@ -102,6 +109,7 @@ class ChatHuggingFace_ChatModels implements INode { const hfTopK = nodeData.inputs?.hfTopK as string const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string const endpoint = nodeData.inputs?.endpoint as string + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) @@ -119,6 +127,7 @@ class ChatHuggingFace_ChatModels implements INode { if (endpoint) obj.endpoint = endpoint const huggingFace = new HuggingFaceInference(obj) + if (cache) huggingFace.cache = cache return huggingFace } } diff --git a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts index a6ddfae4..78fe31dd 100644 --- a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts +++ b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts @@ -2,6 +2,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { OpenAIChat } from 'langchain/llms/openai' import { OpenAIChatInput } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatLocalAI_ChatModels implements INode { label: string @@ -17,13 +19,19 @@ class ChatLocalAI_ChatModels implements INode { constructor() { this.label = 'ChatLocalAI' this.name = 'chatLocalAI' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatLocalAI' this.icon = 'localai.png' this.category = 'Chat Models' this.description = 'Use local LLMs like llama.cpp, gpt4all using LocalAI' this.baseClasses = [this.type, 'BaseChatModel', ...getBaseClasses(OpenAIChat)] this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Base Path', name: 'basePath', @@ -78,8 +86,9 @@ class ChatLocalAI_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const timeout = nodeData.inputs?.timeout as string const basePath = nodeData.inputs?.basePath as string + const cache = nodeData.inputs?.llmCache as BaseCache - const obj: Partial & { openAIApiKey?: string } = { + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey: 'sk-' @@ -88,6 +97,7 @@ class ChatLocalAI_ChatModels implements INode { if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) if (topP) obj.topP = parseFloat(topP) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache const model = new OpenAIChat(obj, { basePath }) diff --git a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts index ca081ff4..a9eae481 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatOpenAI, OpenAIChatInput } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatOpenAI_ChatModels implements INode { label: string @@ -17,7 +19,7 @@ class ChatOpenAI_ChatModels implements INode { constructor() { this.label = 'ChatOpenAI' this.name = 'chatOpenAI' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatOpenAI' this.icon = 'openai.png' this.category = 'Chat Models' @@ -30,6 +32,12 @@ class ChatOpenAI_ChatModels implements INode { credentialNames: ['openAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -151,7 +159,9 @@ class ChatOpenAI_ChatModels implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const obj: Partial & { openAIApiKey?: string } = { + const cache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey, @@ -163,6 +173,7 @@ class ChatOpenAI_ChatModels implements INode { if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty) if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache let parsedBaseOptions: any | undefined = undefined diff --git a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts index 29c1181a..6f8d1310 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatOpenAI, OpenAIChatInput } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatOpenAICustom_ChatModels implements INode { label: string @@ -17,7 +19,7 @@ class ChatOpenAICustom_ChatModels implements INode { constructor() { this.label = 'ChatOpenAI Custom' this.name = 'chatOpenAICustom' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatOpenAI-Custom' this.icon = 'openai.png' this.category = 'Chat Models' @@ -31,6 +33,12 @@ class ChatOpenAICustom_ChatModels implements INode { optional: true } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -113,11 +121,12 @@ class ChatOpenAICustom_ChatModels implements INode { const streaming = nodeData.inputs?.streaming as boolean const basePath = nodeData.inputs?.basepath as string const baseOptions = nodeData.inputs?.baseOptions + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const obj: Partial & { openAIApiKey?: string } = { + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey, @@ -129,6 +138,7 @@ class ChatOpenAICustom_ChatModels implements INode { if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty) if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache let parsedBaseOptions: any | undefined = undefined From e01acbc3e8f1bf866e168890066c9183afefaf25 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 15:53:06 +0530 Subject: [PATCH 35/55] Renaming of Category, Class Names and File names from LLMCache to Cache as this functionality is applicable to both LLM and Chat Models. --- .../InMemoryCache/InMemoryCache.ts} | 12 ++++++------ .../InMemoryCache}/memorycache.png | Bin .../MomentoCache/MomentoCache.ts} | 12 ++++++------ .../MomentoCache}/momento.png | Bin .../RedisCache/RedisCache.ts} | 12 ++++++------ .../LLMRedisCache => cache/RedisCache}/redis.svg | 0 .../UpstashRedisCache/UpstashRedisCache.ts} | 12 ++++++------ .../UpstashRedisCache}/upstash.png | Bin 8 files changed, 24 insertions(+), 24 deletions(-) rename packages/components/nodes/{llmcache/LLMInMemoryCache/LLMInMemoryCache.ts => cache/InMemoryCache/InMemoryCache.ts} (71%) rename packages/components/nodes/{llmcache/LLMInMemoryCache => cache/InMemoryCache}/memorycache.png (100%) rename packages/components/nodes/{llmcache/LLMMomentoCache/LLMMomentoCache.ts => cache/MomentoCache/MomentoCache.ts} (86%) rename packages/components/nodes/{llmcache/LLMMomentoCache => cache/MomentoCache}/momento.png (100%) rename packages/components/nodes/{llmcache/LLMRedisCache/LLMRedisCache.ts => cache/RedisCache/RedisCache.ts} (85%) rename packages/components/nodes/{llmcache/LLMRedisCache => cache/RedisCache}/redis.svg (100%) rename packages/components/nodes/{llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts => cache/UpstashRedisCache/UpstashRedisCache.ts} (82%) rename packages/components/nodes/{llmcache/LLMUpstashRedisCache => cache/UpstashRedisCache}/upstash.png (100%) diff --git a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts similarity index 71% rename from packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts rename to packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts index 44133486..8bed721f 100644 --- a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts +++ b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts @@ -1,8 +1,8 @@ import { INode, INodeParams } from '../../../src/Interface' -import { InMemoryCache } from 'langchain/cache' +import { InMemoryCache as LangchainInMemoryCache } from 'langchain/cache' import { getBaseClasses } from '../../../src' -class LLMInMemoryCache implements INode { +class InMemoryCache implements INode { label: string name: string version: number @@ -18,19 +18,19 @@ class LLMInMemoryCache implements INode { this.label = 'Local (Builtin) Cache' this.name = 'localCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'memorycache.png' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(InMemoryCache)] this.inputs = [] } async init(): Promise { if (!this.inMemoryCache) { - this.inMemoryCache = InMemoryCache.global() + this.inMemoryCache = LangchainInMemoryCache.global() } return this.inMemoryCache } } -module.exports = { nodeClass: LLMInMemoryCache } +module.exports = { nodeClass: InMemoryCache } diff --git a/packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png b/packages/components/nodes/cache/InMemoryCache/memorycache.png similarity index 100% rename from packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png rename to packages/components/nodes/cache/InMemoryCache/memorycache.png diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts similarity index 86% rename from packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts rename to packages/components/nodes/cache/MomentoCache/MomentoCache.ts index f8fd61fb..37d90941 100644 --- a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -1,8 +1,8 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' -import { MomentoCache } from 'langchain/cache/momento' +import { MomentoCache as LangchainMomentoCache } from 'langchain/cache/momento' import { CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk' -class LLMMomentoCache implements INode { +class MomentoCache implements INode { label: string name: string version: number @@ -18,9 +18,9 @@ class LLMMomentoCache implements INode { this.label = 'Momento Cache' this.name = 'momentoCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'momento.png' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(MomentoCache)] this.credential = { label: 'Connect Credential', @@ -47,7 +47,7 @@ class LLMMomentoCache implements INode { defaultTtlSeconds: 60 * 60 * 24 }) - let momentoCache = await MomentoCache.fromProps({ + let momentoCache = await LangchainMomentoCache.fromProps({ client, cacheName: cacheName }) @@ -55,4 +55,4 @@ class LLMMomentoCache implements INode { } } -module.exports = { nodeClass: LLMMomentoCache } +module.exports = { nodeClass: MomentoCache } diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/momento.png b/packages/components/nodes/cache/MomentoCache/momento.png similarity index 100% rename from packages/components/nodes/llmcache/LLMMomentoCache/momento.png rename to packages/components/nodes/cache/MomentoCache/momento.png diff --git a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts similarity index 85% rename from packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts rename to packages/components/nodes/cache/RedisCache/RedisCache.ts index a7208977..d0143d76 100644 --- a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -1,8 +1,8 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' -import { RedisCache } from 'langchain/cache/ioredis' +import { RedisCache as LangchainRedisCache } from 'langchain/cache/ioredis' import { Redis } from 'ioredis' -class LLMRedisCache implements INode { +class RedisCache implements INode { label: string name: string version: number @@ -18,9 +18,9 @@ class LLMRedisCache implements INode { this.label = 'Redis LLM Cache' this.name = 'redisCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'redis.svg' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(RedisCache)] this.credential = { label: 'Connect Credential', @@ -45,8 +45,8 @@ class LLMRedisCache implements INode { username, password }) - return new RedisCache(client) + return new LangchainRedisCache(client) } } -module.exports = { nodeClass: LLMRedisCache } +module.exports = { nodeClass: RedisCache } diff --git a/packages/components/nodes/llmcache/LLMRedisCache/redis.svg b/packages/components/nodes/cache/RedisCache/redis.svg similarity index 100% rename from packages/components/nodes/llmcache/LLMRedisCache/redis.svg rename to packages/components/nodes/cache/RedisCache/redis.svg diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts similarity index 82% rename from packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts rename to packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts index 8914b2a1..a9322b1e 100644 --- a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts +++ b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts @@ -1,7 +1,7 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' -import { UpstashRedisCache } from 'langchain/cache/upstash_redis' +import { UpstashRedisCache as LangchainUpstashRedisCache } from 'langchain/cache/upstash_redis' -class LLMUpstashRedisCache implements INode { +class UpstashRedisCache implements INode { label: string name: string version: number @@ -17,9 +17,9 @@ class LLMUpstashRedisCache implements INode { this.label = 'Upstash Redis LLM Cache' this.name = 'upstashRedisCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'upstash.png' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(UpstashRedisCache)] this.credential = { label: 'Connect Credential', @@ -36,7 +36,7 @@ class LLMUpstashRedisCache implements INode { const upstashConnectionUrl = getCredentialParam('upstashConnectionUrl', credentialData, nodeData) const upstashToken = getCredentialParam('upstashConnectionToken', credentialData, nodeData) - const cache = new UpstashRedisCache({ + const cache = new LangchainUpstashRedisCache({ config: { url: upstashConnectionUrl, token: upstashToken @@ -46,4 +46,4 @@ class LLMUpstashRedisCache implements INode { } } -module.exports = { nodeClass: LLMUpstashRedisCache } +module.exports = { nodeClass: UpstashRedisCache } diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png b/packages/components/nodes/cache/UpstashRedisCache/upstash.png similarity index 100% rename from packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png rename to packages/components/nodes/cache/UpstashRedisCache/upstash.png From a7574913422c518da259a35d39a85bb623871ae5 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 11:58:37 +0100 Subject: [PATCH 36/55] Update MomentoCache.ts Base Class --- packages/components/nodes/cache/MomentoCache/MomentoCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts index 37d90941..722f7340 100644 --- a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -21,7 +21,7 @@ class MomentoCache implements INode { this.type = 'Cache' this.icon = 'momento.png' this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(MomentoCache)] + this.baseClasses = [this.type, ...getBaseClasses(LangchainMomentoCache)] this.credential = { label: 'Connect Credential', name: 'credential', From 132913f50b26524e43c4d1eb6c48619a34920c5a Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 11:58:57 +0100 Subject: [PATCH 37/55] Update RedisCache.ts Base Class --- packages/components/nodes/cache/RedisCache/RedisCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index d0143d76..46980acb 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -21,7 +21,7 @@ class RedisCache implements INode { this.type = 'Cache' this.icon = 'redis.svg' this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(RedisCache)] + this.baseClasses = [this.type, ...getBaseClasses(LangchainRedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', From 40b06cd43af8baf6aaf9f0b57393810245debb01 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 11:59:14 +0100 Subject: [PATCH 38/55] Update UpstashRedisCache.ts Base Class --- .../nodes/cache/UpstashRedisCache/UpstashRedisCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts index a9322b1e..b4ba71a5 100644 --- a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts +++ b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts @@ -20,7 +20,7 @@ class UpstashRedisCache implements INode { this.type = 'Cache' this.icon = 'upstash.png' this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(UpstashRedisCache)] + this.baseClasses = [this.type, ...getBaseClasses(LangchainUpstashRedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', From 77899b956ec16f7b1b5a1771384f182673013bb9 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:00:44 +0100 Subject: [PATCH 39/55] Update index.ts --- packages/server/src/utils/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 98802cde..664f110b 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -477,7 +477,7 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: */ export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[], nodes: IReactFlowNode[]): boolean => { for (const node of startingNodes) { - if (node.data.category === 'LLM Cache') return true + if (node.data.category === 'Cache') return true for (const inputName in node.data.inputs) { const inputVariables = getInputVariables(node.data.inputs[inputName]) if (inputVariables.length > 0) return true From 643adb59792bb37b4716b3ce5e8922b72ebac8d9 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:08:23 +0100 Subject: [PATCH 40/55] Update MomentoCache.ts type --- packages/components/nodes/cache/MomentoCache/MomentoCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts index 722f7340..70ac9da7 100644 --- a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -18,7 +18,7 @@ class MomentoCache implements INode { this.label = 'Momento Cache' this.name = 'momentoCache' this.version = 1.0 - this.type = 'Cache' + this.type = 'MomentoCache' this.icon = 'momento.png' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainMomentoCache)] From abce51353b302ef6c3138741aaa6eb73bf9388a0 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:08:51 +0100 Subject: [PATCH 41/55] Update RedisCache.ts type --- packages/components/nodes/cache/RedisCache/RedisCache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index 46980acb..c1b08be6 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -15,10 +15,10 @@ class RedisCache implements INode { credential: INodeParams constructor() { - this.label = 'Redis LLM Cache' + this.label = 'Redis Cache' this.name = 'redisCache' this.version = 1.0 - this.type = 'Cache' + this.type = 'RedisCache' this.icon = 'redis.svg' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainRedisCache)] From 12159f6730711ab0b0690c72787305e30d823c85 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:09:16 +0100 Subject: [PATCH 42/55] Update UpstashRedisCache.ts type --- .../nodes/cache/UpstashRedisCache/UpstashRedisCache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts index b4ba71a5..eb5a9e2f 100644 --- a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts +++ b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts @@ -14,10 +14,10 @@ class UpstashRedisCache implements INode { credential: INodeParams constructor() { - this.label = 'Upstash Redis LLM Cache' + this.label = 'Upstash Redis Cache' this.name = 'upstashRedisCache' this.version = 1.0 - this.type = 'Cache' + this.type = 'UpstashRedisCache' this.icon = 'upstash.png' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainUpstashRedisCache)] From 7d4337724d6ab323a09fb96451989b115b2638b3 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 22:59:43 +0530 Subject: [PATCH 43/55] Updating of Type LLMCache to BaseCache and renaming vars for clarity --- .../nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts | 4 ++-- .../chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts | 4 ++-- .../nodes/chatmodels/Bittensor/Bittensor.ts | 4 ++-- .../nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts | 4 ++-- .../chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts | 4 ++-- .../ChatGoogleVertexAI/ChatGoogleVertexAI.ts | 4 ++-- .../chatmodels/ChatHuggingFace/ChatHuggingFace.ts | 4 ++-- .../nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts | 4 ++-- .../nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts | 4 ++-- .../chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts | 4 ++-- .../components/nodes/llms/AWSBedrock/AWSBedrock.ts | 13 +++++++++++-- .../nodes/llms/Azure OpenAI/AzureOpenAI.ts | 8 ++++---- .../components/nodes/llms/Bittensor/Bittensor.ts | 8 ++++---- packages/components/nodes/llms/Cohere/Cohere.ts | 8 ++++---- .../components/nodes/llms/GooglePaLM/GooglePaLM.ts | 8 ++++---- .../nodes/llms/GoogleVertexAI/GoogleVertexAI.ts | 8 ++++---- .../HuggingFaceInference/HuggingFaceInference.ts | 8 ++++---- packages/components/nodes/llms/OpenAI/OpenAI.ts | 8 ++++---- .../components/nodes/llms/Replicate/Replicate.ts | 8 ++++---- 19 files changed, 63 insertions(+), 54 deletions(-) diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts index ba4bdd8a..16fbc8dc 100644 --- a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -44,7 +44,7 @@ class AWSChatBedrock_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -138,7 +138,7 @@ class AWSChatBedrock_ChatModels implements INode { const iModel = nodeData.inputs?.model as string const iTemperature = nodeData.inputs?.temperature as string const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: BaseBedrockInput & BaseLLMParams = { region: iRegion, diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index 5acf4dce..99e151e6 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -36,7 +36,7 @@ class AzureChatOpenAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -115,7 +115,7 @@ class AzureChatOpenAI_ChatModels implements INode { const presencePenalty = nodeData.inputs?.presencePenalty as string const timeout = nodeData.inputs?.timeout as string const streaming = nodeData.inputs?.streaming as boolean - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const azureOpenAIApiKey = getCredentialParam('azureOpenAIApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts index 89c37157..36b084e6 100644 --- a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts +++ b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts @@ -27,7 +27,7 @@ class Bittensor_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -42,7 +42,7 @@ class Bittensor_ChatModels implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial = { systemPrompt: system_prompt diff --git a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts index 039b437b..f16968b6 100644 --- a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts +++ b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts @@ -35,7 +35,7 @@ class ChatAnthropic_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -143,7 +143,7 @@ class ChatAnthropic_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const streaming = nodeData.inputs?.streaming as boolean - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const anthropicApiKey = getCredentialParam('anthropicApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts index 8ee3fbb8..121406c7 100644 --- a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts +++ b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts @@ -34,7 +34,7 @@ class ChatGooglePaLM_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -103,7 +103,7 @@ class ChatGooglePaLM_ChatModels implements INode { const temperature = nodeData.inputs?.temperature as string const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts index 4f876239..6b070bd9 100644 --- a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts +++ b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts @@ -38,7 +38,7 @@ class GoogleVertexAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -120,7 +120,7 @@ class GoogleVertexAI_ChatModels implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: GoogleVertexAIChatInput = { temperature: parseFloat(temperature), diff --git a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts index d9c0d22f..153c5d10 100644 --- a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts +++ b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts @@ -34,7 +34,7 @@ class ChatHuggingFace_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -109,7 +109,7 @@ class ChatHuggingFace_ChatModels implements INode { const hfTopK = nodeData.inputs?.hfTopK as string const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string const endpoint = nodeData.inputs?.endpoint as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts index 78fe31dd..18ed409b 100644 --- a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts +++ b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts @@ -29,7 +29,7 @@ class ChatLocalAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -86,7 +86,7 @@ class ChatLocalAI_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const timeout = nodeData.inputs?.timeout as string const basePath = nodeData.inputs?.basePath as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), diff --git a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts index a9eae481..f74bd642 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts @@ -35,7 +35,7 @@ class ChatOpenAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -159,7 +159,7 @@ class ChatOpenAI_ChatModels implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), diff --git a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts index 6f8d1310..2a01a2e5 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts @@ -36,7 +36,7 @@ class ChatOpenAICustom_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -121,7 +121,7 @@ class ChatOpenAICustom_ChatModels implements INode { const streaming = nodeData.inputs?.streaming as boolean const basePath = nodeData.inputs?.basepath as string const baseOptions = nodeData.inputs?.baseOptions - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts index 68ee7ed2..8f57daac 100644 --- a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts +++ b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts @@ -2,6 +2,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { Bedrock } from 'langchain/llms/bedrock' import { BaseBedrockInput } from 'langchain/dist/util/bedrock' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' /** * I had to run the following to build the component @@ -39,6 +41,12 @@ class AWSBedrock_LLMs implements INode { optional: true } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'BaseCache', + optional: true + }, { label: 'Region', name: 'region', @@ -130,8 +138,8 @@ class AWSBedrock_LLMs implements INode { const iModel = nodeData.inputs?.model as string const iTemperature = nodeData.inputs?.temperature as string const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string - - const obj: Partial = { + const cache = nodeData.inputs?.cache as BaseCache + const obj: Partial & BaseLLMParams = { model: iModel, region: iRegion, temperature: parseFloat(iTemperature), @@ -157,6 +165,7 @@ class AWSBedrock_LLMs implements INode { sessionToken: credentialApiSession } } + if (cache) obj.cache = cache const amazonBedrock = new Bedrock(obj) return amazonBedrock diff --git a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts index e5cca769..f50e3d95 100644 --- a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts +++ b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts @@ -33,8 +33,8 @@ class AzureOpenAI_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -170,7 +170,7 @@ class AzureOpenAI_LLMs implements INode { const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData) const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & Partial = { temperature: parseFloat(temperature), @@ -188,7 +188,7 @@ class AzureOpenAI_LLMs implements INode { if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new OpenAI(obj) return model diff --git a/packages/components/nodes/llms/Bittensor/Bittensor.ts b/packages/components/nodes/llms/Bittensor/Bittensor.ts index 84401e59..e6cc2bb6 100644 --- a/packages/components/nodes/llms/Bittensor/Bittensor.ts +++ b/packages/components/nodes/llms/Bittensor/Bittensor.ts @@ -27,8 +27,8 @@ class Bittensor_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -52,13 +52,13 @@ class Bittensor_LLMs implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string const topResponses = Number(nodeData.inputs?.topResponses as number) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams = { systemPrompt: system_prompt, topResponses: topResponses } - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new NIBittensorLLM(obj) return model diff --git a/packages/components/nodes/llms/Cohere/Cohere.ts b/packages/components/nodes/llms/Cohere/Cohere.ts index 8b4c0ac2..3fde0af0 100644 --- a/packages/components/nodes/llms/Cohere/Cohere.ts +++ b/packages/components/nodes/llms/Cohere/Cohere.ts @@ -33,8 +33,8 @@ class Cohere_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -92,7 +92,7 @@ class Cohere_LLMs implements INode { const temperature = nodeData.inputs?.temperature as string const modelName = nodeData.inputs?.modelName as string const maxTokens = nodeData.inputs?.maxTokens as string - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) @@ -103,7 +103,7 @@ class Cohere_LLMs implements INode { if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) if (modelName) obj.model = modelName if (temperature) obj.temperature = parseFloat(temperature) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new Cohere(obj) return model } diff --git a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts index d916c09f..d3212a1c 100644 --- a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts +++ b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts @@ -32,8 +32,8 @@ class GooglePaLM_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -132,7 +132,7 @@ class GooglePaLM_LLMs implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const stopSequencesObj = nodeData.inputs?.stopSequencesObj - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) @@ -146,7 +146,7 @@ class GooglePaLM_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache let parsedStopSequences: any | undefined = undefined if (stopSequencesObj) { diff --git a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts index 41b18475..6b6d534b 100644 --- a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts +++ b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts @@ -37,8 +37,8 @@ class GoogleVertexAI_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -127,7 +127,7 @@ class GoogleVertexAI_LLMs implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial = { temperature: parseFloat(temperature), @@ -137,7 +137,7 @@ class GoogleVertexAI_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new GoogleVertexAI(obj) return model diff --git a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts index 9d6226e2..8dcf021b 100644 --- a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts +++ b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts @@ -33,8 +33,8 @@ class HuggingFaceInference_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -113,7 +113,7 @@ class HuggingFaceInference_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial = { model, @@ -128,7 +128,7 @@ class HuggingFaceInference_LLMs implements INode { if (endpoint) obj.endpoint = endpoint const huggingFace = new HuggingFaceInference(obj) - if (llmCache) huggingFace.cache = llmCache + if (cache) huggingFace.cache = cache return huggingFace } diff --git a/packages/components/nodes/llms/OpenAI/OpenAI.ts b/packages/components/nodes/llms/OpenAI/OpenAI.ts index 607ebeb4..9109dd40 100644 --- a/packages/components/nodes/llms/OpenAI/OpenAI.ts +++ b/packages/components/nodes/llms/OpenAI/OpenAI.ts @@ -34,8 +34,8 @@ class OpenAI_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -157,7 +157,7 @@ class OpenAI_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), @@ -174,7 +174,7 @@ class OpenAI_LLMs implements INode { if (batchSize) obj.batchSize = parseInt(batchSize, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache let parsedBaseOptions: any | undefined = undefined if (baseOptions) { diff --git a/packages/components/nodes/llms/Replicate/Replicate.ts b/packages/components/nodes/llms/Replicate/Replicate.ts index fd1eb6f7..fd5373a1 100644 --- a/packages/components/nodes/llms/Replicate/Replicate.ts +++ b/packages/components/nodes/llms/Replicate/Replicate.ts @@ -34,8 +34,8 @@ class Replicate_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -111,7 +111,7 @@ class Replicate_LLMs implements INode { const name = modelName.split(':')[0].split('/').pop() const org = modelName.split(':')[0].split('/')[0] - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: ReplicateInput & BaseLLMParams = { model: `${org}/${name}:${version}`, @@ -130,7 +130,7 @@ class Replicate_LLMs implements INode { } if (Object.keys(inputs).length) obj.input = inputs - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new Replicate(obj) return model From 644bd09ef2a659687daa6431a52edca8ca693a7b Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 23:03:00 +0530 Subject: [PATCH 44/55] Removing InMemoryCache and code cleanup in MomentoCache --- .../cache/InMemoryCache/InMemoryCache.ts | 36 ------------------ .../nodes/cache/InMemoryCache/memorycache.png | Bin 2717 -> 0 bytes .../nodes/cache/MomentoCache/MomentoCache.ts | 1 - 3 files changed, 37 deletions(-) delete mode 100644 packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts delete mode 100644 packages/components/nodes/cache/InMemoryCache/memorycache.png diff --git a/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts deleted file mode 100644 index 8bed721f..00000000 --- a/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { INode, INodeParams } from '../../../src/Interface' -import { InMemoryCache as LangchainInMemoryCache } from 'langchain/cache' -import { getBaseClasses } from '../../../src' - -class InMemoryCache implements INode { - label: string - name: string - version: number - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - inMemoryCache: any - - constructor() { - this.label = 'Local (Builtin) Cache' - this.name = 'localCache' - this.version = 1.0 - this.type = 'Cache' - this.icon = 'memorycache.png' - this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(InMemoryCache)] - this.inputs = [] - } - - async init(): Promise { - if (!this.inMemoryCache) { - this.inMemoryCache = LangchainInMemoryCache.global() - } - return this.inMemoryCache - } -} - -module.exports = { nodeClass: InMemoryCache } diff --git a/packages/components/nodes/cache/InMemoryCache/memorycache.png b/packages/components/nodes/cache/InMemoryCache/memorycache.png deleted file mode 100644 index aaeecd6fb100be3a10b3d1faca046f9fa409f018..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2717 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 XQt;1#;KI))00000NkvXXu0mjfl~Wzs diff --git a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts index 70ac9da7..9aa82e82 100644 --- a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -36,7 +36,6 @@ class MomentoCache implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const apiKey = getCredentialParam('momentoApiKey', credentialData, nodeData) const cacheName = getCredentialParam('momentoCache', credentialData, nodeData) - const endPoint = getCredentialParam('momentoEndpoint', credentialData, nodeData) // See https://github.com/momentohq/client-sdk-javascript for connection options const client = new CacheClient({ From 303e5653dd403f408dbac04011b49af7ff5fb972 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Mon, 9 Oct 2023 16:44:04 +0100 Subject: [PATCH 45/55] update cacheValue to capture other outputs object --- packages/components/src/handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index a102b473..1ae16050 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -191,7 +191,7 @@ export class CustomChainHandler extends BaseCallbackHandler { Callback Order is "Chain Start -> Chain End" for cached responses. */ if (this.cachedResponse) { - const cachedValue = outputs.text as string + const cachedValue: string = outputs.text ?? outputs.response ?? outputs.output ?? '' //split at whitespace, and keep the whitespace. This is to preserve the original formatting. const result = cachedValue.split(/(\s+)/) result.forEach((token: string, index: number) => { From 719c8c4e55d8f570918c2c0aa2a4c35893591ea1 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Mon, 9 Oct 2023 18:25:36 +0100 Subject: [PATCH 46/55] only emit token when parentId is undefined --- packages/components/src/handler.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 1ae16050..3b1952d6 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -177,21 +177,17 @@ export class CustomChainHandler extends BaseCallbackHandler { } handleLLMEnd() { - /* send the end event from handleChainEnd */ - // this.socketIO.to(this.socketIOClientId).emit('end') + this.socketIO.to(this.socketIOClientId).emit('end') } - handleChainEnd(outputs: ChainValues): void | Promise { - if (this.returnSourceDocuments) { - this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) - } + handleChainEnd(outputs: ChainValues, _: string, parentRunId?: string): void | Promise { /* Langchain does not call handleLLMStart, handleLLMEnd, handleLLMNewToken when the chain is cached. Callback Order is "Chain Start -> LLM Start --> LLM Token --> LLM End -> Chain End" for normal responses. Callback Order is "Chain Start -> Chain End" for cached responses. */ - if (this.cachedResponse) { - const cachedValue: string = outputs.text ?? outputs.response ?? outputs.output ?? '' + if (this.cachedResponse && parentRunId === undefined) { + const cachedValue = outputs.text ?? outputs.response ?? outputs.output ?? outputs.output_text //split at whitespace, and keep the whitespace. This is to preserve the original formatting. const result = cachedValue.split(/(\s+)/) result.forEach((token: string, index: number) => { @@ -200,8 +196,15 @@ export class CustomChainHandler extends BaseCallbackHandler { } this.socketIO.to(this.socketIOClientId).emit('token', token) }) + if (this.returnSourceDocuments) { + this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) + } + this.socketIO.to(this.socketIOClientId).emit('end') + } else { + if (this.returnSourceDocuments) { + this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) + } } - this.socketIO.to(this.socketIOClientId).emit('end') } } From 41caf2aee75067fae735724dfed84ba8972a6efd Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 9 Oct 2023 19:56:15 +0100 Subject: [PATCH 47/55] add memory fix --- .../agents/ConversationalAgent/ConversationalAgent.ts | 8 ++++++-- .../ConversationalRetrievalAgent.ts | 6 +++++- .../agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts | 8 ++++++-- .../nodes/chains/ConversationChain/ConversationChain.ts | 8 ++++++-- .../ConversationalRetrievalQAChain.ts | 6 +++++- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts index 661ef151..00f825d4 100644 --- a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts +++ b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts @@ -95,8 +95,12 @@ class ConversationalAgent_Agents implements INode { const callbacks = await additionalCallbacks(nodeData, options) if (options && options.chatHistory) { - memory.chatHistory = mapChatHistory(options) - executor.memory = memory + const chatHistoryClassName = memory.chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + memory.chatHistory = mapChatHistory(options) + executor.memory = memory + } } const result = await executor.call({ input }, [...callbacks]) diff --git a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts index 3d70a2d3..4a908d7f 100644 --- a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts +++ b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts @@ -82,7 +82,11 @@ class ConversationalRetrievalAgent_Agents implements INode { if (executor.memory) { ;(executor.memory as any).memoryKey = 'chat_history' ;(executor.memory as any).outputKey = 'output' - ;(executor.memory as any).chatHistory = mapChatHistory(options) + const chatHistoryClassName = (executor.memory as any).chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + ;(executor.memory as any).chatHistory = mapChatHistory(options) + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) diff --git a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts index c1bd32ec..c920c399 100644 --- a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts +++ b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts @@ -81,8 +81,12 @@ class OpenAIFunctionAgent_Agents implements INode { const memory = nodeData.inputs?.memory as BaseChatMemory if (options && options.chatHistory) { - memory.chatHistory = mapChatHistory(options) - executor.memory = memory + const chatHistoryClassName = memory.chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + memory.chatHistory = mapChatHistory(options) + executor.memory = memory + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index b26603e2..1cd15c9a 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -106,8 +106,12 @@ class ConversationChain_Chains implements INode { const memory = nodeData.inputs?.memory as BufferMemory if (options && options.chatHistory) { - memory.chatHistory = mapChatHistory(options) - chain.memory = memory + const chatHistoryClassName = memory.chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + memory.chatHistory = mapChatHistory(options) + chain.memory = memory + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) diff --git a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts index 1b4675bd..9a8c1b18 100644 --- a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts +++ b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts @@ -179,7 +179,11 @@ class ConversationalRetrievalQAChain_Chains implements INode { const obj = { question: input } if (options && options.chatHistory && chain.memory) { - ;(chain.memory as any).chatHistory = mapChatHistory(options) + const chatHistoryClassName = (chain.memory as any).chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + ;(chain.memory as any).chatHistory = mapChatHistory(options) + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) From 4caa9ba9abf6996b3bc16727df2da08cf56fe5c6 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 00:01:28 +0100 Subject: [PATCH 48/55] update marketplace llm with cache --- .../chatflows/API Agent OpenAI.json | 24 +++++++-- .../marketplaces/chatflows/API Agent.json | 36 ++++++++++--- .../marketplaces/chatflows/Antonym.json | 16 ++++-- .../marketplaces/chatflows/AutoGPT.json | 12 ++++- .../marketplaces/chatflows/BabyAGI.json | 12 ++++- .../marketplaces/chatflows/CSV Agent.json | 12 ++++- .../marketplaces/chatflows/ChatGPTPlugin.json | 12 ++++- .../marketplaces/chatflows/Claude LLM.json | 16 ++++-- .../chatflows/Conversational Agent.json | 12 ++++- .../Conversational Retrieval Agent.json | 12 ++++- .../Conversational Retrieval QA Chain.json | 16 ++++-- .../chatflows/Flowise Docs QnA.json | 12 ++++- .../chatflows/HuggingFace LLM Chain.json | 16 ++++-- .../marketplaces/chatflows/Local QnA.json | 16 ++++-- .../chatflows/Long Term Memory.json | 16 ++++-- .../marketplaces/chatflows/MRKLAgent.json | 12 ++++- .../chatflows/Metadata Filter Load.json | 16 ++++-- .../chatflows/Metadata Filter Upsert.json | 12 ++++- .../chatflows/Multi Prompt Chain.json | 12 ++++- .../chatflows/Multi Retrieval QA Chain.json | 12 ++++- .../chatflows/Multiple VectorDB.json | 52 ++++++++++++++----- .../marketplaces/chatflows/OpenAI Agent.json | 12 ++++- .../Prompt Chaining with VectorStore.json | 32 +++++++++--- .../chatflows/Prompt Chaining.json | 32 +++++++++--- .../marketplaces/chatflows/Replicate LLM.json | 16 ++++-- .../marketplaces/chatflows/SQL DB Chain.json | 12 ++++- .../chatflows/Simple Conversation Chain.json | 16 ++++-- .../chatflows/Simple LLM Chain.json | 16 ++++-- .../marketplaces/chatflows/Translator.json | 16 ++++-- .../chatflows/Vectara LLM Chain Upload.json | 12 ++++- .../marketplaces/chatflows/WebBrowser.json | 32 +++++++++--- .../marketplaces/chatflows/WebPage QnA.json | 12 ++++- .../marketplaces/chatflows/Zapier NLA.json | 12 ++++- 33 files changed, 452 insertions(+), 124 deletions(-) diff --git a/packages/server/marketplaces/chatflows/API Agent OpenAI.json b/packages/server/marketplaces/chatflows/API Agent OpenAI.json index 01e3d8f9..b2ff977b 100644 --- a/packages/server/marketplaces/chatflows/API Agent OpenAI.json +++ b/packages/server/marketplaces/chatflows/API Agent OpenAI.json @@ -89,7 +89,7 @@ "id": "chatOpenAI_1", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -201,7 +201,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -392,7 +400,7 @@ "id": "chatOpenAI_2", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -504,7 +512,15 @@ "id": "chatOpenAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_2-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/API Agent.json b/packages/server/marketplaces/chatflows/API Agent.json index b9862add..c37aaff2 100644 --- a/packages/server/marketplaces/chatflows/API Agent.json +++ b/packages/server/marketplaces/chatflows/API Agent.json @@ -397,7 +397,7 @@ "id": "chatOpenAI_2", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -509,7 +509,15 @@ "id": "chatOpenAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_2-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -551,7 +559,7 @@ "id": "chatOpenAI_1", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -663,7 +671,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -705,7 +721,7 @@ "id": "chatOpenAI_3", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -817,7 +833,15 @@ "id": "chatOpenAI_3-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_3-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Antonym.json b/packages/server/marketplaces/chatflows/Antonym.json index 95d3c151..5f8ff7a8 100644 --- a/packages/server/marketplaces/chatflows/Antonym.json +++ b/packages/server/marketplaces/chatflows/Antonym.json @@ -169,14 +169,14 @@ "id": "chatOpenAI_0", "position": { "x": 1226.7977900193628, - "y": 48.01100655894436 + "y": -22.01100655894436 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -288,7 +288,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -313,7 +321,7 @@ "selected": false, "positionAbsolute": { "x": 1226.7977900193628, - "y": 48.01100655894436 + "y": -22.01100655894436 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/AutoGPT.json b/packages/server/marketplaces/chatflows/AutoGPT.json index 53837151..4fb706ab 100644 --- a/packages/server/marketplaces/chatflows/AutoGPT.json +++ b/packages/server/marketplaces/chatflows/AutoGPT.json @@ -252,7 +252,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -364,7 +364,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/BabyAGI.json b/packages/server/marketplaces/chatflows/BabyAGI.json index c2897531..04410b82 100644 --- a/packages/server/marketplaces/chatflows/BabyAGI.json +++ b/packages/server/marketplaces/chatflows/BabyAGI.json @@ -78,7 +78,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -190,7 +190,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/CSV Agent.json b/packages/server/marketplaces/chatflows/CSV Agent.json index 1515fcad..37764a53 100644 --- a/packages/server/marketplaces/chatflows/CSV Agent.json +++ b/packages/server/marketplaces/chatflows/CSV Agent.json @@ -70,7 +70,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -182,7 +182,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/ChatGPTPlugin.json b/packages/server/marketplaces/chatflows/ChatGPTPlugin.json index 471853ba..1f00ff5f 100644 --- a/packages/server/marketplaces/chatflows/ChatGPTPlugin.json +++ b/packages/server/marketplaces/chatflows/ChatGPTPlugin.json @@ -215,7 +215,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -327,7 +327,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Claude LLM.json b/packages/server/marketplaces/chatflows/Claude LLM.json index 243d2600..b7989815 100644 --- a/packages/server/marketplaces/chatflows/Claude LLM.json +++ b/packages/server/marketplaces/chatflows/Claude LLM.json @@ -141,14 +141,14 @@ "id": "chatAnthropic_0", "position": { "x": 800.5525382783799, - "y": -76.7988221837009 + "y": -130.7988221837009 }, "type": "customNode", "data": { "id": "chatAnthropic_0", "label": "ChatAnthropic", "name": "chatAnthropic", - "version": 1, + "version": 2, "type": "ChatAnthropic", "baseClasses": ["ChatAnthropic", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -258,7 +258,15 @@ "id": "chatAnthropic_0-input-topK-number" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatAnthropic_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "claude-2", "temperature": 0.9, @@ -280,7 +288,7 @@ "selected": false, "positionAbsolute": { "x": 800.5525382783799, - "y": -76.7988221837009 + "y": -130.7988221837009 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Conversational Agent.json b/packages/server/marketplaces/chatflows/Conversational Agent.json index 55475b3e..d18f2ac0 100644 --- a/packages/server/marketplaces/chatflows/Conversational Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Agent.json @@ -157,7 +157,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -269,7 +269,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json index dcf344d1..7c5c38e2 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json @@ -13,7 +13,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": "0", diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json index bf27e443..725ca7c9 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json @@ -7,14 +7,14 @@ "id": "chatOpenAI_0", "position": { "x": 1184.1176114500388, - "y": -44.15535835370571 + "y": -74.15535835370571 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -150,7 +158,7 @@ }, "positionAbsolute": { "x": 1184.1176114500388, - "y": -44.15535835370571 + "y": -74.15535835370571 }, "selected": false, "dragging": false diff --git a/packages/server/marketplaces/chatflows/Flowise Docs QnA.json b/packages/server/marketplaces/chatflows/Flowise Docs QnA.json index f8b274a1..2928d29d 100644 --- a/packages/server/marketplaces/chatflows/Flowise Docs QnA.json +++ b/packages/server/marketplaces/chatflows/Flowise Docs QnA.json @@ -386,7 +386,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -498,7 +498,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json b/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json index 6e159a28..e51e1ee0 100644 --- a/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json +++ b/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json @@ -148,14 +148,14 @@ "id": "huggingFaceInference_LLMs_0", "position": { "x": 498.8594464193537, - "y": -44.91050256311678 + "y": -94.91050256311678 }, "type": "customNode", "data": { "id": "huggingFaceInference_LLMs_0", "label": "HuggingFace Inference", "name": "huggingFaceInference_LLMs", - "version": 1, + "version": 2, "type": "HuggingFaceInference", "baseClasses": ["HuggingFaceInference", "LLM", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -232,7 +232,15 @@ "id": "huggingFaceInference_LLMs_0-input-frequencyPenalty-number" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "huggingFaceInference_LLMs_0-input-cache-BaseCache" + } + ], "inputs": { "model": "tiiuae/falcon-7b-instruct", "endpoint": "", @@ -256,7 +264,7 @@ "selected": false, "positionAbsolute": { "x": 498.8594464193537, - "y": -44.91050256311678 + "y": -94.91050256311678 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Local QnA.json b/packages/server/marketplaces/chatflows/Local QnA.json index 9d9f5ec8..21bdf744 100644 --- a/packages/server/marketplaces/chatflows/Local QnA.json +++ b/packages/server/marketplaces/chatflows/Local QnA.json @@ -265,14 +265,14 @@ "id": "chatLocalAI_0", "position": { "x": 1191.9512064167336, - "y": -44.05401001663306 + "y": -94.05401001663306 }, "type": "customNode", "data": { "id": "chatLocalAI_0", "label": "ChatLocalAI", "name": "chatLocalAI", - "version": 1, + "version": 2, "type": "ChatLocalAI", "baseClasses": ["ChatLocalAI", "BaseChatModel", "LLM", "BaseLLM", "BaseLanguageModel", "BaseLangChain"], "category": "Chat Models", @@ -325,7 +325,15 @@ "id": "chatLocalAI_0-input-timeout-number" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatLocalAI_0-input-cache-BaseCache" + } + ], "inputs": { "basePath": "http://localhost:8080/v1", "modelName": "ggml-gpt4all-j.bin", @@ -348,7 +356,7 @@ "selected": false, "positionAbsolute": { "x": 1191.9512064167336, - "y": -44.05401001663306 + "y": -94.05401001663306 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Long Term Memory.json b/packages/server/marketplaces/chatflows/Long Term Memory.json index 07669f82..6f22c00a 100644 --- a/packages/server/marketplaces/chatflows/Long Term Memory.json +++ b/packages/server/marketplaces/chatflows/Long Term Memory.json @@ -115,14 +115,14 @@ "id": "chatOpenAI_0", "position": { "x": 1554.3875781165111, - "y": -14.792508259787212 + "y": -74.792508259787212 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -234,7 +234,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -259,7 +267,7 @@ "selected": false, "positionAbsolute": { "x": 1554.3875781165111, - "y": -14.792508259787212 + "y": -74.792508259787212 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/MRKLAgent.json b/packages/server/marketplaces/chatflows/MRKLAgent.json index f851b0ed..697e4919 100644 --- a/packages/server/marketplaces/chatflows/MRKLAgent.json +++ b/packages/server/marketplaces/chatflows/MRKLAgent.json @@ -156,7 +156,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -268,7 +268,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Metadata Filter Load.json b/packages/server/marketplaces/chatflows/Metadata Filter Load.json index b6ca91e3..43438d6b 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter Load.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter Load.json @@ -113,14 +113,14 @@ "id": "chatOpenAI_0", "position": { "x": 1197.7264239788542, - "y": -16.177600120515933 + "y": -76.177600120515933 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -232,7 +232,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -257,7 +265,7 @@ "selected": false, "positionAbsolute": { "x": 1197.7264239788542, - "y": -16.177600120515933 + "y": -76.177600120515933 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json b/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json index e70b11f7..525fa1b9 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json @@ -436,7 +436,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -548,7 +548,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Multi Prompt Chain.json b/packages/server/marketplaces/chatflows/Multi Prompt Chain.json index cf86df5b..e1063dcf 100644 --- a/packages/server/marketplaces/chatflows/Multi Prompt Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Prompt Chain.json @@ -278,7 +278,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -390,7 +390,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json index f5604bf6..36240e39 100644 --- a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json @@ -679,7 +679,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -791,7 +791,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Multiple VectorDB.json b/packages/server/marketplaces/chatflows/Multiple VectorDB.json index ac4643aa..b4dedfdd 100644 --- a/packages/server/marketplaces/chatflows/Multiple VectorDB.json +++ b/packages/server/marketplaces/chatflows/Multiple VectorDB.json @@ -321,14 +321,14 @@ "id": "openAI_2", "position": { "x": 520.8471510168988, - "y": -1282.1183473852964 + "y": -1362.1183473852964 }, "type": "customNode", "data": { "id": "openAI_2", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -436,7 +436,15 @@ "id": "openAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_2-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -463,7 +471,7 @@ "selected": false, "positionAbsolute": { "x": 520.8471510168988, - "y": -1282.1183473852964 + "y": -1362.1183473852964 }, "dragging": false }, @@ -557,7 +565,7 @@ "id": "chromaExistingIndex_0", "position": { "x": 509.55198017578016, - "y": -732.42003311752 + "y": -782.42003311752 }, "type": "customNode", "data": { @@ -638,7 +646,7 @@ "selected": false, "positionAbsolute": { "x": 509.55198017578016, - "y": -732.42003311752 + "y": -782.42003311752 }, "dragging": false }, @@ -732,14 +740,14 @@ "id": "openAI_3", "position": { "x": 504.808358369027, - "y": -197.78194663790197 + "y": -257.78194663790197 }, "type": "customNode", "data": { "id": "openAI_3", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -847,7 +855,15 @@ "id": "openAI_3-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_3-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -874,7 +890,7 @@ "selected": false, "positionAbsolute": { "x": 504.808358369027, - "y": -197.78194663790197 + "y": -257.78194663790197 }, "dragging": false }, @@ -993,14 +1009,14 @@ "id": "openAI_4", "position": { "x": 1619.5346765785587, - "y": 292.29615581180684 + "y": 352.29615581180684 }, "type": "customNode", "data": { "id": "openAI_4", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -1108,7 +1124,15 @@ "id": "openAI_4-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_4-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -1135,7 +1159,7 @@ "selected": false, "positionAbsolute": { "x": 1619.5346765785587, - "y": 292.29615581180684 + "y": 352.29615581180684 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/OpenAI Agent.json b/packages/server/marketplaces/chatflows/OpenAI Agent.json index 91d5d38c..9a98d29d 100644 --- a/packages/server/marketplaces/chatflows/OpenAI Agent.json +++ b/packages/server/marketplaces/chatflows/OpenAI Agent.json @@ -281,7 +281,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -393,7 +393,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json index 9d6838eb..2af61190 100644 --- a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json +++ b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json @@ -260,13 +260,13 @@ "id": "chatOpenAI_0", "position": { "x": 335.7621848973805, - "y": -651.7411273245009 + "y": -721.7411273245009 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -385,7 +385,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": 0.9, @@ -411,7 +419,7 @@ "dragging": false, "positionAbsolute": { "x": 335.7621848973805, - "y": -651.7411273245009 + "y": -721.7411273245009 } }, { @@ -420,13 +428,13 @@ "id": "chatOpenAI_1", "position": { "x": 1765.2801848172305, - "y": -667.9261054149061 + "y": -737.9261054149061 }, "type": "customNode", "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -545,7 +553,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": 0.9, @@ -571,7 +587,7 @@ "dragging": false, "positionAbsolute": { "x": 1765.2801848172305, - "y": -667.9261054149061 + "y": -737.9261054149061 } }, { diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining.json b/packages/server/marketplaces/chatflows/Prompt Chaining.json index 5bce9905..77c238ad 100644 --- a/packages/server/marketplaces/chatflows/Prompt Chaining.json +++ b/packages/server/marketplaces/chatflows/Prompt Chaining.json @@ -289,14 +289,14 @@ "id": "openAI_1", "position": { "x": 791.6102007244282, - "y": -13.71386876566092 + "y": -83.71386876566092 }, "type": "customNode", "data": { "id": "openAI_1", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -404,7 +404,15 @@ "id": "openAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -431,7 +439,7 @@ "selected": false, "positionAbsolute": { "x": 791.6102007244282, - "y": -13.71386876566092 + "y": -83.71386876566092 }, "dragging": false }, @@ -441,14 +449,14 @@ "id": "openAI_2", "position": { "x": 1571.148617508543, - "y": -20.372437481171687 + "y": -90.372437481171687 }, "type": "customNode", "data": { "id": "openAI_2", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -556,7 +564,15 @@ "id": "openAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_2-input-cache-BaseCache" + } + ], "default": "gpt-3.5-turbo-instruct", "inputs": { "modelName": "gpt-3.5-turbo-instruct", @@ -584,7 +600,7 @@ "selected": false, "positionAbsolute": { "x": 1571.148617508543, - "y": -20.372437481171687 + "y": -90.372437481171687 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Replicate LLM.json b/packages/server/marketplaces/chatflows/Replicate LLM.json index c5a0ac8f..0049214c 100644 --- a/packages/server/marketplaces/chatflows/Replicate LLM.json +++ b/packages/server/marketplaces/chatflows/Replicate LLM.json @@ -148,13 +148,13 @@ "id": "replicate_0", "position": { "x": 623.313978186024, - "y": -72.92788335022428 + "y": -142.92788335022428 }, "type": "customNode", "data": { "id": "replicate_0", "label": "Replicate", - "version": 1, + "version": 2, "name": "replicate", "type": "Replicate", "baseClasses": ["Replicate", "BaseChatModel", "LLM", "BaseLLM", "BaseLanguageModel", "Runnable"], @@ -226,7 +226,15 @@ "id": "replicate_0-input-additionalInputs-json" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "replicate_0-input-cache-BaseCache" + } + ], "inputs": { "model": "a16z-infra/llama13b-v2-chat:df7690f1994d94e96ad9d568eac121aecf50684a0b0963b25a41cc40061269e5", "temperature": 0.7, @@ -249,7 +257,7 @@ "selected": false, "positionAbsolute": { "x": 623.313978186024, - "y": -72.92788335022428 + "y": -142.92788335022428 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/SQL DB Chain.json b/packages/server/marketplaces/chatflows/SQL DB Chain.json index 646db5d4..3b32efe0 100644 --- a/packages/server/marketplaces/chatflows/SQL DB Chain.json +++ b/packages/server/marketplaces/chatflows/SQL DB Chain.json @@ -13,7 +13,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", diff --git a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json index 2c41a54f..57ff348a 100644 --- a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json +++ b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json @@ -64,14 +64,14 @@ "id": "chatOpenAI_0", "position": { "x": 754.8942497823595, - "y": -70.76607584232393 + "y": -140 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -183,7 +183,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -208,7 +216,7 @@ "selected": false, "positionAbsolute": { "x": 754.8942497823595, - "y": -70.76607584232393 + "y": -140 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Simple LLM Chain.json b/packages/server/marketplaces/chatflows/Simple LLM Chain.json index 21d5ab68..f3db04ef 100644 --- a/packages/server/marketplaces/chatflows/Simple LLM Chain.json +++ b/packages/server/marketplaces/chatflows/Simple LLM Chain.json @@ -148,14 +148,14 @@ "id": "openAI_0", "position": { "x": 513.3297923232442, - "y": -42.67554802812833 + "y": -112.67554802812833 }, "type": "customNode", "data": { "id": "openAI_0", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -263,7 +263,15 @@ "id": "openAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -290,7 +298,7 @@ "selected": false, "positionAbsolute": { "x": 513.3297923232442, - "y": -42.67554802812833 + "y": -112.67554802812833 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Translator.json b/packages/server/marketplaces/chatflows/Translator.json index dc2ee6ba..b552aceb 100644 --- a/packages/server/marketplaces/chatflows/Translator.json +++ b/packages/server/marketplaces/chatflows/Translator.json @@ -157,14 +157,14 @@ "id": "chatOpenAI_0", "position": { "x": 436.97058562345904, - "y": 99.96180150605153 + "y": 29.96180150605153 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -276,7 +276,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -301,7 +309,7 @@ "selected": false, "positionAbsolute": { "x": 436.97058562345904, - "y": 99.96180150605153 + "y": 29.96180150605153 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json index 47cfef87..dc1c1e17 100644 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json @@ -124,7 +124,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -230,7 +230,15 @@ "id": "chatOpenAI_0-input-baseOptions-json" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0.5", diff --git a/packages/server/marketplaces/chatflows/WebBrowser.json b/packages/server/marketplaces/chatflows/WebBrowser.json index 95743f9f..b784f9ab 100644 --- a/packages/server/marketplaces/chatflows/WebBrowser.json +++ b/packages/server/marketplaces/chatflows/WebBrowser.json @@ -194,14 +194,14 @@ "id": "chatOpenAI_0", "position": { "x": 734.7477982032904, - "y": -400.9979556765114 + "y": -470.9979556765114 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -313,7 +313,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -338,7 +346,7 @@ "selected": false, "positionAbsolute": { "x": 734.7477982032904, - "y": -400.9979556765114 + "y": -470.9979556765114 }, "dragging": false }, @@ -432,14 +440,14 @@ "id": "chatOpenAI_1", "position": { "x": 68.312124033115, - "y": -169.65476709991256 + "y": -239.65476709991256 }, "type": "customNode", "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -551,7 +559,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -576,7 +592,7 @@ "selected": false, "positionAbsolute": { "x": 68.312124033115, - "y": -169.65476709991256 + "y": -239.65476709991256 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index 812f0bd5..66bac37f 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -13,7 +13,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": "0.9", diff --git a/packages/server/marketplaces/chatflows/Zapier NLA.json b/packages/server/marketplaces/chatflows/Zapier NLA.json index 182b24ae..49527da2 100644 --- a/packages/server/marketplaces/chatflows/Zapier NLA.json +++ b/packages/server/marketplaces/chatflows/Zapier NLA.json @@ -115,7 +115,7 @@ "id": "openAI_0", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -223,7 +223,15 @@ "id": "openAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, From a9148c23a42df98c2d86ed4bc5ce2a6148ad3448 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar H M Date: Tue, 10 Oct 2023 16:53:47 +0530 Subject: [PATCH 49/55] Update SqlDatabaseChain.ts --- .../SqlDatabaseChain/SqlDatabaseChain.ts | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts index ba9cd7f8..6fc42b45 100644 --- a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts +++ b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts @@ -7,28 +7,10 @@ import { BaseLanguageModel } from 'langchain/base_language' import { PromptTemplate, PromptTemplateInput } from 'langchain/prompts' import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler' import { DataSourceOptions } from 'typeorm/data-source' +import { DEFAULT_SQL_DATABASE_PROMPT } from 'langchain/chains/sql_db' type DatabaseType = 'sqlite' | 'postgres' | 'mssql' | 'mysql' -const defaultPrompt = `Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. You can order the results by a relevant column to return the most interesting examples in the database. - -Never query for all the columns from a specific table, only ask for a the few relevant columns given the question. - -Pay attention to use only the column names that you can see in the schema description. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table. - -Use the following format: - -Question: "Question here" -SQLQuery: "SQL Query to run" -SQLResult: "Result of the SQLQuery" -Answer: "Final answer here" - -Only use the tables listed below. - -{table_info} - -Question: {input}` - class SqlDatabaseChain_Chains implements INode { label: string name: string @@ -131,7 +113,7 @@ class SqlDatabaseChain_Chains implements INode { warning: 'Prompt must include 3 input variables: {input}, {dialect}, {table_info}. You can refer to official guide from description above', rows: 4, - placeholder: defaultPrompt, + placeholder: DEFAULT_SQL_DATABASE_PROMPT.template + DEFAULT_SQL_DATABASE_PROMPT.templateFormat, additionalParams: true, optional: true } From ff3b862c9f247674942f5592f28f09bd8bd87711 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar H M Date: Tue, 10 Oct 2023 19:18:24 +0530 Subject: [PATCH 50/55] Update SqlDatabaseChain.ts --- .../nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts index 6fc42b45..ac33fa0e 100644 --- a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts +++ b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts @@ -1,5 +1,5 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' -import { SqlDatabaseChain, SqlDatabaseChainInput } from 'langchain/chains/sql_db' +import { SqlDatabaseChain, SqlDatabaseChainInput, DEFAULT_SQL_DATABASE_PROMPT } from 'langchain/chains/sql_db' import { getBaseClasses, getInputVariables } from '../../../src/utils' import { DataSource } from 'typeorm' import { SqlDatabase } from 'langchain/sql_db' @@ -7,7 +7,6 @@ import { BaseLanguageModel } from 'langchain/base_language' import { PromptTemplate, PromptTemplateInput } from 'langchain/prompts' import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler' import { DataSourceOptions } from 'typeorm/data-source' -import { DEFAULT_SQL_DATABASE_PROMPT } from 'langchain/chains/sql_db' type DatabaseType = 'sqlite' | 'postgres' | 'mssql' | 'mysql' From 9af7775d0e0efe2c15f88d78bb2bee2c7838ac47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Stan=C4=9Bk?= Date: Tue, 10 Oct 2023 16:30:46 +0200 Subject: [PATCH 51/55] text output for Text File and Plain Text components --- .../documentloaders/PlainText/PlainText.ts | 32 ++++++++++++++--- .../nodes/documentloaders/Text/Text.ts | 34 ++++++++++++++++--- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/packages/components/nodes/documentloaders/PlainText/PlainText.ts b/packages/components/nodes/documentloaders/PlainText/PlainText.ts index 261f2d98..53953698 100644 --- a/packages/components/nodes/documentloaders/PlainText/PlainText.ts +++ b/packages/components/nodes/documentloaders/PlainText/PlainText.ts @@ -1,6 +1,7 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { TextSplitter } from 'langchain/text_splitter' import { Document } from 'langchain/document' +import { handleEscapeCharacters } from '../../../src' class PlainText_DocumentLoaders implements INode { label: string @@ -12,6 +13,7 @@ class PlainText_DocumentLoaders implements INode { category: string baseClasses: string[] inputs: INodeParams[] + outputs: INodeOutputsValue[] constructor() { this.label = 'Plain Text' @@ -45,12 +47,25 @@ class PlainText_DocumentLoaders implements INode { additionalParams: true } ] + this.outputs = [ + { + label: 'Document', + name: 'document', + baseClasses: this.baseClasses + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } async init(nodeData: INodeData): Promise { const textSplitter = nodeData.inputs?.textSplitter as TextSplitter const text = nodeData.inputs?.text as string const metadata = nodeData.inputs?.metadata + const output = nodeData.outputs?.output as string let alldocs: Document>[] = [] @@ -65,9 +80,9 @@ class PlainText_DocumentLoaders implements INode { ) } + let finaldocs: Document>[] = [] if (metadata) { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) - let finaldocs: Document>[] = [] for (const doc of alldocs) { const newdoc = { ...doc, @@ -78,10 +93,19 @@ class PlainText_DocumentLoaders implements INode { } finaldocs.push(newdoc) } - return finaldocs + } else { + finaldocs = alldocs } - return alldocs + if (output === 'document') { + return finaldocs + } else { + let finaltext = '' + for (const doc of finaldocs) { + finaltext += `${doc.pageContent}\n` + } + return handleEscapeCharacters(finaltext, false) + } } } diff --git a/packages/components/nodes/documentloaders/Text/Text.ts b/packages/components/nodes/documentloaders/Text/Text.ts index dacf087c..01b6ae5d 100644 --- a/packages/components/nodes/documentloaders/Text/Text.ts +++ b/packages/components/nodes/documentloaders/Text/Text.ts @@ -1,6 +1,8 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { TextSplitter } from 'langchain/text_splitter' import { TextLoader } from 'langchain/document_loaders/fs/text' +import { Document } from 'langchain/document' +import { handleEscapeCharacters } from '../../../src' class Text_DocumentLoaders implements INode { label: string @@ -12,6 +14,7 @@ class Text_DocumentLoaders implements INode { category: string baseClasses: string[] inputs: INodeParams[] + outputs: INodeOutputsValue[] constructor() { this.label = 'Text File' @@ -43,12 +46,25 @@ class Text_DocumentLoaders implements INode { additionalParams: true } ] + this.outputs = [ + { + label: 'Document', + name: 'document', + baseClasses: this.baseClasses + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } async init(nodeData: INodeData): Promise { const textSplitter = nodeData.inputs?.textSplitter as TextSplitter const txtFileBase64 = nodeData.inputs?.txtFile as string const metadata = nodeData.inputs?.metadata + const output = nodeData.outputs?.output as string let alldocs = [] let files: string[] = [] @@ -75,9 +91,9 @@ class Text_DocumentLoaders implements INode { } } + let finaldocs: Document>[] = [] if (metadata) { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) - let finaldocs = [] for (const doc of alldocs) { const newdoc = { ...doc, @@ -88,9 +104,19 @@ class Text_DocumentLoaders implements INode { } finaldocs.push(newdoc) } - return finaldocs + } else { + finaldocs = alldocs + } + + if (output === 'document') { + return finaldocs + } else { + let finaltext = '' + for (const doc of finaldocs) { + finaltext += `${doc.pageContent}\n` + } + return handleEscapeCharacters(finaltext, false) } - return alldocs } } From 9cbdcff8a89f1879a602277257219e9fb02bf15b Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 16:57:29 +0100 Subject: [PATCH 52/55] =?UTF-8?q?=F0=9F=A5=B3=20flowise-components@1.3.8?= =?UTF-8?q?=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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 e3c4380a..cf545ec3 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.3.7", + "version": "1.3.8", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", From bf5d9a01be4c2d8c121a8be6963c1de887ba8743 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 16:58:18 +0100 Subject: [PATCH 53/55] =?UTF-8?q?=F0=9F=A5=B3=20flowise-ui@1.3.5=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index f0101d2c..239cc3ce 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "flowise-ui", - "version": "1.3.4", + "version": "1.3.5", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://flowiseai.com", "author": { From 4a0918519554016ac60503157320d37b6b9894ce Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 16:58:44 +0100 Subject: [PATCH 54/55] =?UTF-8?q?=F0=9F=A5=B3=20flowise@1.3.7=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- packages/server/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 210a95c4..e123cc68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.6", + "version": "1.3.7", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ diff --git a/packages/server/package.json b/packages/server/package.json index 6f17ad61..a5fb994c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.6", + "version": "1.3.7", "description": "Flowiseai Server", "main": "dist/index", "types": "dist/index.d.ts", From 4d312cb13b21104b4aabd45333199966e750f520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Stan=C4=9Bk?= Date: Wed, 11 Oct 2023 08:16:50 +0200 Subject: [PATCH 55/55] version --- .../components/nodes/documentloaders/PlainText/PlainText.ts | 2 +- packages/components/nodes/documentloaders/Text/Text.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/documentloaders/PlainText/PlainText.ts b/packages/components/nodes/documentloaders/PlainText/PlainText.ts index 53953698..c2adceeb 100644 --- a/packages/components/nodes/documentloaders/PlainText/PlainText.ts +++ b/packages/components/nodes/documentloaders/PlainText/PlainText.ts @@ -18,7 +18,7 @@ class PlainText_DocumentLoaders implements INode { constructor() { this.label = 'Plain Text' this.name = 'plainText' - this.version = 1.0 + this.version = 2.0 this.type = 'Document' this.icon = 'plaintext.svg' this.category = 'Document Loaders' diff --git a/packages/components/nodes/documentloaders/Text/Text.ts b/packages/components/nodes/documentloaders/Text/Text.ts index 01b6ae5d..c3e3b61e 100644 --- a/packages/components/nodes/documentloaders/Text/Text.ts +++ b/packages/components/nodes/documentloaders/Text/Text.ts @@ -19,7 +19,7 @@ class Text_DocumentLoaders implements INode { constructor() { this.label = 'Text File' this.name = 'textFile' - this.version = 1.0 + this.version = 2.0 this.type = 'Document' this.icon = 'textFile.svg' this.category = 'Document Loaders'