diff --git a/package.json b/package.json index 909eb345..649a9a47 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.4.2", + "version": "1.4.3", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ diff --git a/packages/components/credentials/RedisCacheApi.credential.ts b/packages/components/credentials/RedisCacheApi.credential.ts index e09a94e7..4d1a2498 100644 --- a/packages/components/credentials/RedisCacheApi.credential.ts +++ b/packages/components/credentials/RedisCacheApi.credential.ts @@ -8,7 +8,7 @@ class RedisCacheApi implements INodeCredential { inputs: INodeParams[] constructor() { - this.label = 'Redis Cache API' + this.label = 'Redis API' this.name = 'redisCacheApi' this.version = 1.0 this.inputs = [ diff --git a/packages/components/credentials/RedisCacheUrlApi.credential.ts b/packages/components/credentials/RedisCacheUrlApi.credential.ts index fc2e2eb2..e016d78f 100644 --- a/packages/components/credentials/RedisCacheUrlApi.credential.ts +++ b/packages/components/credentials/RedisCacheUrlApi.credential.ts @@ -8,7 +8,7 @@ class RedisCacheUrlApi implements INodeCredential { inputs: INodeParams[] constructor() { - this.label = 'Redis Cache URL' + this.label = 'Redis URL' this.name = 'redisCacheUrlApi' this.version = 1.0 this.inputs = [ @@ -16,7 +16,7 @@ class RedisCacheUrlApi implements INodeCredential { label: 'Redis URL', name: 'redisUrl', type: 'string', - default: '127.0.0.1' + default: 'redis://localhost:6379' } ] } diff --git a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts index 00f825d4..8a2329b5 100644 --- a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts +++ b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts @@ -3,7 +3,7 @@ import { initializeAgentExecutorWithOptions, AgentExecutor, InitializeAgentExecu import { Tool } from 'langchain/tools' import { BaseChatMemory } from 'langchain/memory' import { getBaseClasses, mapChatHistory } from '../../../src/utils' -import { BaseLanguageModel } from 'langchain/base_language' +import { BaseChatModel } from 'langchain/chat_models/base' import { flatten } from 'lodash' import { additionalCallbacks } from '../../../src/handler' @@ -29,7 +29,7 @@ class ConversationalAgent_Agents implements INode { constructor() { this.label = 'Conversational Agent' this.name = 'conversationalAgent' - this.version = 1.0 + this.version = 2.0 this.type = 'AgentExecutor' this.category = 'Agents' this.icon = 'agent.svg' @@ -45,7 +45,7 @@ class ConversationalAgent_Agents implements INode { { label: 'Language Model', name: 'model', - type: 'BaseLanguageModel' + type: 'BaseChatModel' }, { label: 'Memory', @@ -65,7 +65,7 @@ class ConversationalAgent_Agents implements INode { } async init(nodeData: INodeData): Promise { - const model = nodeData.inputs?.model as BaseLanguageModel + const model = nodeData.inputs?.model as BaseChatModel let tools = nodeData.inputs?.tools as Tool[] tools = flatten(tools) const memory = nodeData.inputs?.memory as BaseChatMemory @@ -92,8 +92,6 @@ class ConversationalAgent_Agents implements INode { const executor = nodeData.instance as AgentExecutor const memory = nodeData.inputs?.memory as BaseChatMemory - const callbacks = await additionalCallbacks(nodeData, options) - if (options && options.chatHistory) { const chatHistoryClassName = memory.chatHistory.constructor.name // Only replace when its In-Memory @@ -103,6 +101,10 @@ class ConversationalAgent_Agents implements INode { } } + ;(executor.memory as any).returnMessages = true // Return true for BaseChatModel + + const callbacks = await additionalCallbacks(nodeData, options) + const result = await executor.call({ input }, [...callbacks]) return result?.output } diff --git a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts index c6354e18..643c6a65 100644 --- a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts +++ b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts @@ -82,6 +82,8 @@ 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).returnMessages = true + const chatHistoryClassName = (executor.memory as any).chatHistory.constructor.name // Only replace when its In-Memory if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { diff --git a/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts b/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts index b119599d..35299057 100644 --- a/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts +++ b/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts @@ -23,7 +23,7 @@ class OpenAIAssistant_Agents implements INode { constructor() { this.label = 'OpenAI Assistant' this.name = 'openAIAssistant' - this.version = 1.0 + this.version = 2.0 this.type = 'OpenAIAssistant' this.category = 'Agents' this.icon = 'openai.png' @@ -41,6 +41,15 @@ class OpenAIAssistant_Agents implements INode { name: 'tools', type: 'Tool', list: true + }, + { + label: 'Disable File Download', + name: 'disableFileDownload', + type: 'boolean', + description: + 'Messages can contain text, images, or files. In some cases, you may want to prevent others from downloading the files. Learn more from OpenAI File Annotation docs', + optional: true, + additionalParams: true } ] } @@ -119,6 +128,8 @@ class OpenAIAssistant_Agents implements INode { const selectedAssistantId = nodeData.inputs?.selectedAssistant as string const appDataSource = options.appDataSource as DataSource const databaseEntities = options.databaseEntities as IDatabaseEntity + const disableFileDownload = nodeData.inputs?.disableFileDownload as boolean + let tools = nodeData.inputs?.tools tools = flatten(tools) const formattedTools = tools?.map((tool: any) => formatToOpenAIAssistantTool(tool)) ?? [] @@ -310,7 +321,7 @@ class OpenAIAssistant_Agents implements INode { const dirPath = path.join(getUserHome(), '.flowise', 'openai-assistant') - // Iterate over the annotations and add footnotes + // Iterate over the annotations for (let index = 0; index < annotations.length; index++) { const annotation = annotations[index] let filePath = '' @@ -323,11 +334,13 @@ class OpenAIAssistant_Agents implements INode { // eslint-disable-next-line no-useless-escape const fileName = cited_file.filename.split(/[\/\\]/).pop() ?? cited_file.filename filePath = path.join(getUserHome(), '.flowise', 'openai-assistant', fileName) - await downloadFile(cited_file, filePath, dirPath, openAIApiKey) - fileAnnotations.push({ - filePath, - fileName - }) + if (!disableFileDownload) { + await downloadFile(cited_file, filePath, dirPath, openAIApiKey) + fileAnnotations.push({ + filePath, + fileName + }) + } } else { const file_path = (annotation as OpenAI.Beta.Threads.Messages.MessageContentText.Text.FilePath).file_path if (file_path) { @@ -335,11 +348,13 @@ class OpenAIAssistant_Agents implements INode { // eslint-disable-next-line no-useless-escape const fileName = cited_file.filename.split(/[\/\\]/).pop() ?? cited_file.filename filePath = path.join(getUserHome(), '.flowise', 'openai-assistant', fileName) - await downloadFile(cited_file, filePath, dirPath, openAIApiKey) - fileAnnotations.push({ - filePath, - fileName - }) + if (!disableFileDownload) { + await downloadFile(cited_file, filePath, dirPath, openAIApiKey) + fileAnnotations.push({ + filePath, + fileName + }) + } } } @@ -351,6 +366,9 @@ class OpenAIAssistant_Agents implements INode { } else { returnVal += content.text.value } + + const lenticularBracketRegex = /【[^】]*】/g + returnVal = returnVal.replace(lenticularBracketRegex, '') } else { const content = assistantMessages[0].content[i] as MessageContentImageFile const fileId = content.image_file.file_id diff --git a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts index 25a540e8..96ba7ea3 100644 --- a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts +++ b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts @@ -87,6 +87,8 @@ class OpenAIFunctionAgent_Agents implements INode { } } + ;(executor.memory as any).returnMessages = true // Return true for BaseChatModel + const loggerHandler = new ConsoleCallbackHandler(options.logger) const callbacks = await additionalCallbacks(nodeData, options) diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index 92a0b5ea..7887ce97 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -106,16 +106,18 @@ class ConversationChain_Chains implements INode { async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { const chain = nodeData.instance as ConversationChain const memory = nodeData.inputs?.memory as BufferMemory + memory.returnMessages = true // Return true for BaseChatModel if (options && options.chatHistory) { const chatHistoryClassName = memory.chatHistory.constructor.name // Only replace when its In-Memory if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { memory.chatHistory = mapChatHistory(options) - chain.memory = memory } } + chain.memory = memory + const loggerHandler = new ConsoleCallbackHandler(options.logger) const callbacks = await additionalCallbacks(nodeData, options) diff --git a/packages/components/nodes/chains/LLMChain/LLMChain.ts b/packages/components/nodes/chains/LLMChain/LLMChain.ts index ee532a27..fd398151 100644 --- a/packages/components/nodes/chains/LLMChain/LLMChain.ts +++ b/packages/components/nodes/chains/LLMChain/LLMChain.ts @@ -1,7 +1,7 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, handleEscapeCharacters } from '../../../src/utils' import { LLMChain } from 'langchain/chains' -import { BaseLanguageModel } from 'langchain/base_language' +import { BaseLanguageModel, BaseLanguageModelCallOptions } from 'langchain/base_language' import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler' import { BaseOutputParser } from 'langchain/schema/output_parser' import { formatResponse, injectOutputParser } from '../../outputparsers/OutputParserHelpers' @@ -141,7 +141,7 @@ class LLMChain_Chains implements INode { const runPrediction = async ( inputVariables: string[], - chain: LLMChain, + chain: LLMChain>, input: string, promptValuesRaw: ICommonObject | undefined, options: ICommonObject, @@ -164,7 +164,7 @@ const runPrediction = async ( if (moderations && moderations.length > 0) { try { // Use the output of the moderation chain as input for the LLM chain - input = await checkInputs(moderations, chain.llm, input) + input = await checkInputs(moderations, input) } catch (e) { await new Promise((resolve) => setTimeout(resolve, 500)) streamResponse(isStreaming, e.message, socketIO, socketIOClientId) diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts index ade46ab9..956fcdb3 100644 --- a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -27,7 +27,7 @@ class AWSChatBedrock_ChatModels implements INode { constructor() { this.label = 'AWS Bedrock' this.name = 'awsChatBedrock' - this.version = 2.0 + this.version = 3.0 this.type = 'AWSChatBedrock' this.icon = 'awsBedrock.png' this.category = 'Chat Models' @@ -97,7 +97,8 @@ class AWSChatBedrock_ChatModels implements INode { options: [ { 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' } + { label: 'anthropic.claude-v2', name: 'anthropic.claude-v2' }, + { label: 'meta.llama2-13b-chat-v1', name: 'meta.llama2-13b-chat-v1' } ], default: 'anthropic.claude-v2' }, @@ -128,12 +129,14 @@ class AWSChatBedrock_ChatModels implements INode { const iTemperature = nodeData.inputs?.temperature as string const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string const cache = nodeData.inputs?.cache as BaseCache + const streaming = nodeData.inputs?.streaming as boolean const obj: BaseBedrockInput & BaseLLMParams = { region: iRegion, model: iModel, maxTokens: parseInt(iMax_tokens_to_sample, 10), - temperature: parseFloat(iTemperature) + temperature: parseFloat(iTemperature), + streaming: streaming ?? true } /** diff --git a/packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts b/packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts index ba2aa5e7..8249d512 100644 --- a/packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts +++ b/packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts @@ -18,7 +18,7 @@ class AWSBedrockEmbedding_Embeddings implements INode { constructor() { this.label = 'AWS Bedrock Embeddings' this.name = 'AWSBedrockEmbeddings' - this.version = 1.0 + this.version = 2.0 this.type = 'AWSBedrockEmbeddings' this.icon = 'awsBedrock.png' this.category = 'Embeddings' @@ -81,7 +81,9 @@ class AWSBedrockEmbedding_Embeddings implements INode { type: 'options', options: [ { label: 'amazon.titan-embed-text-v1', name: 'amazon.titan-embed-text-v1' }, - { label: 'amazon.titan-embed-g1-text-02', name: 'amazon.titan-embed-g1-text-02' } + { label: 'amazon.titan-embed-g1-text-02', name: 'amazon.titan-embed-g1-text-02' }, + { label: 'cohere.embed-english-v3', name: 'cohere.embed-english-v3' }, + { label: 'cohere.embed-multilingual-v3', name: 'cohere.embed-multilingual-v3' } ], default: 'amazon.titan-embed-text-v1' } diff --git a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts index b67219f3..177a32ef 100644 --- a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts +++ b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts @@ -27,7 +27,7 @@ class AWSBedrock_LLMs implements INode { constructor() { this.label = 'AWS Bedrock' this.name = 'awsBedrock' - this.version = 1.2 + this.version = 2.0 this.type = 'AWSBedrock' this.icon = 'awsBedrock.png' this.category = 'LLMs' @@ -98,6 +98,7 @@ class AWSBedrock_LLMs implements INode { { label: 'amazon.titan-tg1-large', name: 'amazon.titan-tg1-large' }, { label: 'amazon.titan-e1t-medium', name: 'amazon.titan-e1t-medium' }, { label: 'cohere.command-text-v14', name: 'cohere.command-text-v14' }, + { label: 'cohere.command-light-text-v14', name: 'cohere.command-light-text-v14' }, { 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' }, diff --git a/packages/components/nodes/memory/DynamoDb/DynamoDb.ts b/packages/components/nodes/memory/DynamoDb/DynamoDb.ts index 68b09b7b..ac4f7602 100644 --- a/packages/components/nodes/memory/DynamoDb/DynamoDb.ts +++ b/packages/components/nodes/memory/DynamoDb/DynamoDb.ts @@ -109,9 +109,8 @@ const initalizeDynamoDB = async (nodeData: INodeData, options: ICommonObject): P }) const memory = new BufferMemoryExtended({ - memoryKey, + memoryKey: memoryKey ?? 'chat_history', chatHistory: dynamoDb, - returnMessages: true, isSessionIdUsingChatMessageId }) return memory diff --git a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts index 7de2ec34..6f800cdc 100644 --- a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts +++ b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts @@ -123,9 +123,8 @@ const initializeMongoDB = async (nodeData: INodeData, options: ICommonObject): P } return new BufferMemoryExtended({ - memoryKey, + memoryKey: memoryKey ?? 'chat_history', chatHistory: mongoDBChatMessageHistory, - returnMessages: true, isSessionIdUsingChatMessageId }) } diff --git a/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts b/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts index c65d729b..bdb62911 100644 --- a/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts @@ -137,7 +137,7 @@ const initalizeRedis = async (nodeData: INodeData, options: ICommonObject): Prom } const memory = new BufferMemoryExtended({ - memoryKey, + memoryKey: memoryKey ?? 'chat_history', chatHistory: redisChatMessageHistory, isSessionIdUsingChatMessageId }) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 6b5fdf66..2b8b4650 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -95,6 +95,7 @@ const initalizeUpstashRedis = async (nodeData: INodeData, options: ICommonObject }) const memory = new BufferMemoryExtended({ + memoryKey: 'chat_history', chatHistory: redisChatMessageHistory, isSessionIdUsingChatMessageId }) diff --git a/packages/components/nodes/moderation/Moderation.ts b/packages/components/nodes/moderation/Moderation.ts index 9c40f55a..9fd2bfde 100644 --- a/packages/components/nodes/moderation/Moderation.ts +++ b/packages/components/nodes/moderation/Moderation.ts @@ -1,13 +1,12 @@ -import { BaseLanguageModel } from 'langchain/base_language' import { Server } from 'socket.io' export abstract class Moderation { - abstract checkForViolations(llm: BaseLanguageModel, input: string): Promise + abstract checkForViolations(input: string): Promise } -export const checkInputs = async (inputModerations: Moderation[], llm: BaseLanguageModel, input: string): Promise => { +export const checkInputs = async (inputModerations: Moderation[], input: string): Promise => { for (const moderation of inputModerations) { - input = await moderation.checkForViolations(llm, input) + input = await moderation.checkForViolations(input) } return input } diff --git a/packages/components/nodes/moderation/OpenAIModeration/OpenAIModeration.ts b/packages/components/nodes/moderation/OpenAIModeration/OpenAIModeration.ts index 5233f174..85b27907 100644 --- a/packages/components/nodes/moderation/OpenAIModeration/OpenAIModeration.ts +++ b/packages/components/nodes/moderation/OpenAIModeration/OpenAIModeration.ts @@ -1,5 +1,5 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' -import { getBaseClasses } from '../../../src' +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src' import { Moderation } from '../Moderation' import { OpenAIModerationRunner } from './OpenAIModerationRunner' @@ -12,6 +12,7 @@ class OpenAIModeration implements INode { icon: string category: string baseClasses: string[] + credential: INodeParams inputs: INodeParams[] constructor() { @@ -19,10 +20,16 @@ class OpenAIModeration implements INode { this.name = 'inputModerationOpenAI' this.version = 1.0 this.type = 'Moderation' - this.icon = 'openai-moderation.png' + this.icon = 'openai.png' this.category = 'Moderation' this.description = 'Check whether content complies with OpenAI usage policies.' this.baseClasses = [this.type, ...getBaseClasses(Moderation)] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['openAIApi'] + } this.inputs = [ { label: 'Error Message', @@ -35,8 +42,11 @@ class OpenAIModeration implements INode { ] } - async init(nodeData: INodeData): Promise { - const runner = new OpenAIModerationRunner() + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) + + const runner = new OpenAIModerationRunner(openAIApiKey) const moderationErrorMessage = nodeData.inputs?.moderationErrorMessage as string if (moderationErrorMessage) runner.setErrorMessage(moderationErrorMessage) return runner diff --git a/packages/components/nodes/moderation/OpenAIModeration/OpenAIModerationRunner.ts b/packages/components/nodes/moderation/OpenAIModeration/OpenAIModerationRunner.ts index c517f419..3a3ec550 100644 --- a/packages/components/nodes/moderation/OpenAIModeration/OpenAIModerationRunner.ts +++ b/packages/components/nodes/moderation/OpenAIModeration/OpenAIModerationRunner.ts @@ -1,18 +1,21 @@ import { Moderation } from '../Moderation' -import { BaseLanguageModel } from 'langchain/base_language' import { OpenAIModerationChain } from 'langchain/chains' export class OpenAIModerationRunner implements Moderation { + private openAIApiKey = '' private moderationErrorMessage: string = "Text was found that violates OpenAI's content policy." - async checkForViolations(llm: BaseLanguageModel, input: string): Promise { - const openAIApiKey = (llm as any).openAIApiKey - if (!openAIApiKey) { + constructor(openAIApiKey: string) { + this.openAIApiKey = openAIApiKey + } + + async checkForViolations(input: string): Promise { + if (!this.openAIApiKey) { throw Error('OpenAI API key not found') } // Create a new instance of the OpenAIModerationChain const moderation = new OpenAIModerationChain({ - openAIApiKey: openAIApiKey, + openAIApiKey: this.openAIApiKey, throwError: false // If set to true, the call will throw an error when the moderation chain detects violating content. If set to false, violating content will return "Text was found that violates OpenAI's content policy.". }) // Send the user's input to the moderation chain and wait for the result diff --git a/packages/components/nodes/moderation/OpenAIModeration/openai-moderation.png b/packages/components/nodes/moderation/OpenAIModeration/openai-moderation.png deleted file mode 100644 index e3b1b282..00000000 Binary files a/packages/components/nodes/moderation/OpenAIModeration/openai-moderation.png and /dev/null differ diff --git a/packages/components/nodes/moderation/OpenAIModeration/openai.png b/packages/components/nodes/moderation/OpenAIModeration/openai.png new file mode 100644 index 00000000..de08a05b Binary files /dev/null and b/packages/components/nodes/moderation/OpenAIModeration/openai.png differ diff --git a/packages/components/nodes/moderation/SimplePromptModeration/SimplePromptModerationRunner.ts b/packages/components/nodes/moderation/SimplePromptModeration/SimplePromptModerationRunner.ts index 7fc251ad..08f9ed1e 100644 --- a/packages/components/nodes/moderation/SimplePromptModeration/SimplePromptModerationRunner.ts +++ b/packages/components/nodes/moderation/SimplePromptModeration/SimplePromptModerationRunner.ts @@ -1,5 +1,4 @@ import { Moderation } from '../Moderation' -import { BaseLanguageModel } from 'langchain/base_language' export class SimplePromptModerationRunner implements Moderation { private readonly denyList: string = '' @@ -13,9 +12,9 @@ export class SimplePromptModerationRunner implements Moderation { this.moderationErrorMessage = moderationErrorMessage } - async checkForViolations(_: BaseLanguageModel, input: string): Promise { + async checkForViolations(input: string): Promise { this.denyList.split('\n').forEach((denyListItem) => { - if (denyListItem && denyListItem !== '' && input.includes(denyListItem)) { + if (denyListItem && denyListItem !== '' && input.toLowerCase().includes(denyListItem.toLowerCase())) { throw Error(this.moderationErrorMessage) } }) diff --git a/packages/components/nodes/outputparsers/OutputParserHelpers.ts b/packages/components/nodes/outputparsers/OutputParserHelpers.ts index a94edddd..8ea77e6b 100644 --- a/packages/components/nodes/outputparsers/OutputParserHelpers.ts +++ b/packages/components/nodes/outputparsers/OutputParserHelpers.ts @@ -1,6 +1,6 @@ import { BaseOutputParser } from 'langchain/schema/output_parser' import { LLMChain } from 'langchain/chains' -import { BaseLanguageModel } from 'langchain/base_language' +import { BaseLanguageModel, BaseLanguageModelCallOptions } from 'langchain/base_language' import { ICommonObject } from '../../src' import { ChatPromptTemplate, FewShotPromptTemplate, PromptTemplate, SystemMessagePromptTemplate } from 'langchain/prompts' @@ -15,7 +15,7 @@ export const formatResponse = (response: string | object): string | object => { export const injectOutputParser = ( outputParser: BaseOutputParser, - chain: LLMChain, + chain: LLMChain>, promptValues: ICommonObject | undefined = undefined ) => { if (outputParser && chain.prompt) { diff --git a/packages/components/nodes/tools/ZapierNLA/ZapierNLA.ts b/packages/components/nodes/tools/ZapierNLA/ZapierNLA.ts deleted file mode 100644 index 31ac989b..00000000 --- a/packages/components/nodes/tools/ZapierNLA/ZapierNLA.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ZapierNLAWrapper, ZapierNLAWrapperParams } from 'langchain/tools' -import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' -import { ZapierToolKit } from 'langchain/agents' -import { getCredentialData, getCredentialParam } from '../../../src' - -class ZapierNLA_Tools implements INode { - label: string - name: string - version: number - description: string - type: string - icon: string - category: string - badge: string - baseClasses: string[] - inputs: INodeParams[] - credential: INodeParams - - constructor() { - this.label = 'Zapier NLA' - this.name = 'zapierNLA' - this.version = 1.0 - this.type = 'ZapierNLA' - this.icon = 'zapier.svg' - this.category = 'Tools' - this.description = "Access to apps and actions on Zapier's platform through a natural language API interface" - this.badge = 'DEPRECATING' - this.inputs = [] - this.credential = { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['zapierNLAApi'] - } - this.baseClasses = [this.type, 'Tool'] - } - - async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - const credentialData = await getCredentialData(nodeData.credential ?? '', options) - const zapierNLAApiKey = getCredentialParam('zapierNLAApiKey', credentialData, nodeData) - - const obj: Partial = { - apiKey: zapierNLAApiKey - } - const zapier = new ZapierNLAWrapper(obj) - const toolkit = await ZapierToolKit.fromZapierNLAWrapper(zapier) - - return toolkit.tools - } -} - -module.exports = { nodeClass: ZapierNLA_Tools } diff --git a/packages/components/nodes/tools/ZapierNLA/zapier.svg b/packages/components/nodes/tools/ZapierNLA/zapier.svg deleted file mode 100644 index 6ed35f29..00000000 --- a/packages/components/nodes/tools/ZapierNLA/zapier.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/packages/components/nodes/vectorstores/InMemory/InMemoryVectorStore.ts b/packages/components/nodes/vectorstores/InMemory/InMemoryVectorStore.ts index 51394613..620c3af7 100644 --- a/packages/components/nodes/vectorstores/InMemory/InMemoryVectorStore.ts +++ b/packages/components/nodes/vectorstores/InMemory/InMemoryVectorStore.ts @@ -31,7 +31,8 @@ class InMemoryVectorStore_VectorStores implements INode { label: 'Document', name: 'document', type: 'Document', - list: true + list: true, + optional: true }, { label: 'Embeddings', diff --git a/packages/components/package.json b/packages/components/package.json index 1d4cea57..bb074392 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.4.2", + "version": "1.4.4", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", @@ -22,7 +22,8 @@ "@dqbd/tiktoken": "^1.0.7", "@elastic/elasticsearch": "^8.9.0", "@getzep/zep-js": "^0.6.3", - "@gomomento/sdk": "^1.40.2", + "@gomomento/sdk": "^1.51.1", + "@gomomento/sdk-core": "^1.51.1", "@google-ai/generativelanguage": "^0.2.1", "@huggingface/inference": "^2.6.1", "@notionhq/client": "^2.2.8", @@ -49,7 +50,7 @@ "html-to-text": "^9.0.5", "husky": "^8.0.3", "ioredis": "^5.3.2", - "langchain": "^0.0.165", + "langchain": "^0.0.196", "langfuse-langchain": "^1.0.31", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", diff --git a/packages/server/marketplaces/chatflows/API Agent OpenAI.json b/packages/server/marketplaces/chatflows/API Agent OpenAI.json index 1a07e60d..26c1961e 100644 --- a/packages/server/marketplaces/chatflows/API Agent OpenAI.json +++ b/packages/server/marketplaces/chatflows/API Agent OpenAI.json @@ -3,7 +3,7 @@ "nodes": [ { "width": 300, - "height": 510, + "height": 491, "id": "openApiChain_1", "position": { "x": 1203.1825726424859, @@ -13,8 +13,8 @@ "data": { "id": "openApiChain_1", "label": "OpenAPI Chain", - "name": "openApiChain", "version": 1, + "name": "openApiChain", "type": "OpenAPIChain", "baseClasses": ["OpenAPIChain", "BaseChain"], "category": "Chains", @@ -78,7 +78,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_1", "position": { "x": 792.3201947594027, @@ -88,8 +88,8 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -259,8 +259,8 @@ "data": { "id": "chainTool_0", "label": "Chain Tool", - "name": "chainTool", "version": 1, + "name": "chainTool", "type": "ChainTool", "baseClasses": ["ChainTool", "DynamicTool", "Tool", "StructuredTool"], "category": "Tools", @@ -397,7 +397,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_2", "position": { "x": 1645.450699499575, @@ -407,8 +407,8 @@ "data": { "id": "chatOpenAI_2", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -578,8 +578,8 @@ "data": { "id": "bufferMemory_0", "label": "Buffer Memory", - "name": "bufferMemory", "version": 1, + "name": "bufferMemory", "type": "BufferMemory", "baseClasses": ["BufferMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", @@ -657,17 +657,6 @@ "label": "" } }, - { - "source": "chatOpenAI_2", - "sourceHandle": "chatOpenAI_2-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", - "target": "openAIFunctionAgent_0", - "targetHandle": "openAIFunctionAgent_0-input-model-BaseChatModel", - "type": "buttonedge", - "id": "chatOpenAI_2-chatOpenAI_2-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-openAIFunctionAgent_0-openAIFunctionAgent_0-input-model-BaseChatModel", - "data": { - "label": "" - } - }, { "source": "bufferMemory_0", "sourceHandle": "bufferMemory_0-output-bufferMemory-BufferMemory|BaseChatMemory|BaseMemory", @@ -678,6 +667,17 @@ "data": { "label": "" } + }, + { + "source": "chatOpenAI_2", + "sourceHandle": "chatOpenAI_2-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", + "target": "openAIFunctionAgent_0", + "targetHandle": "openAIFunctionAgent_0-input-model-ChatOpenAI | AzureChatOpenAI", + "type": "buttonedge", + "id": "chatOpenAI_2-chatOpenAI_2-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-openAIFunctionAgent_0-openAIFunctionAgent_0-input-model-ChatOpenAI | AzureChatOpenAI", + "data": { + "label": "" + } } ] } diff --git a/packages/server/marketplaces/chatflows/API Agent.json b/packages/server/marketplaces/chatflows/API Agent.json index d8fa22ad..93270848 100644 --- a/packages/server/marketplaces/chatflows/API Agent.json +++ b/packages/server/marketplaces/chatflows/API Agent.json @@ -13,8 +13,8 @@ "data": { "id": "getApiChain_0", "label": "GET API Chain", - "name": "getApiChain", "version": 1, + "name": "getApiChain", "type": "GETApiChain", "baseClasses": ["GETApiChain", "BaseChain", "BaseLangChain"], "category": "Chains", @@ -102,8 +102,8 @@ "data": { "id": "chainTool_0", "label": "Chain Tool", - "name": "chainTool", "version": 1, + "name": "chainTool", "type": "ChainTool", "baseClasses": ["ChainTool", "DynamicTool", "Tool", "StructuredTool", "BaseLangChain"], "category": "Tools", @@ -176,8 +176,8 @@ "data": { "id": "bufferMemory_0", "label": "Buffer Memory", - "name": "bufferMemory", "version": 1, + "name": "bufferMemory", "type": "BufferMemory", "baseClasses": ["BufferMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", @@ -233,8 +233,8 @@ "data": { "id": "chainTool_1", "label": "Chain Tool", - "name": "chainTool", "version": 1, + "name": "chainTool", "type": "ChainTool", "baseClasses": ["ChainTool", "DynamicTool", "Tool", "StructuredTool", "BaseLangChain"], "category": "Tools", @@ -307,8 +307,8 @@ "data": { "id": "postApiChain_0", "label": "POST API Chain", - "name": "postApiChain", "version": 1, + "name": "postApiChain", "type": "POSTApiChain", "baseClasses": ["POSTApiChain", "BaseChain", "BaseLangChain"], "category": "Chains", @@ -386,7 +386,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_2", "position": { "x": 572.8941615312035, @@ -396,8 +396,8 @@ "data": { "id": "chatOpenAI_2", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -557,7 +557,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_1", "position": { "x": 828.7788305309582, @@ -567,8 +567,8 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -728,7 +728,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_3", "position": { "x": 1148.338912314111, @@ -738,8 +738,8 @@ "data": { "id": "chatOpenAI_3", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -869,7 +869,7 @@ } ], "inputs": { - "modelName": "gpt-3.5-turbo", + "modelName": "gpt-3.5-turbo-16k", "temperature": 0.9, "maxTokens": "", "topP": "", @@ -902,17 +902,17 @@ "height": 383, "id": "conversationalAgent_0", "position": { - "x": 2114.071431691489, - "y": 941.7926368551367 + "x": 2090.570467632979, + "y": 969.5131357270544 }, "type": "customNode", "data": { "id": "conversationalAgent_0", "label": "Conversational Agent", + "version": 2, "name": "conversationalAgent", - "version": 1, "type": "AgentExecutor", - "baseClasses": ["AgentExecutor", "BaseChain"], + "baseClasses": ["AgentExecutor", "BaseChain", "Runnable"], "category": "Agents", "description": "Conversational agent for a chat model. It will utilize chat specific prompts", "inputParams": [ @@ -938,8 +938,8 @@ { "label": "Language Model", "name": "model", - "type": "BaseLanguageModel", - "id": "conversationalAgent_0-input-model-BaseLanguageModel" + "type": "BaseChatModel", + "id": "conversationalAgent_0-input-model-BaseChatModel" }, { "label": "Memory", @@ -956,21 +956,21 @@ }, "outputAnchors": [ { - "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain", + "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain|Runnable", "name": "conversationalAgent", "label": "AgentExecutor", - "type": "AgentExecutor | BaseChain" + "type": "AgentExecutor | BaseChain | Runnable" } ], "outputs": {}, "selected": false }, "selected": false, - "dragging": false, "positionAbsolute": { - "x": 2114.071431691489, - "y": 941.7926368551367 - } + "x": 2090.570467632979, + "y": 969.5131357270544 + }, + "dragging": false } ], "edges": [ @@ -1044,9 +1044,9 @@ "source": "chatOpenAI_3", "sourceHandle": "chatOpenAI_3-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", "target": "conversationalAgent_0", - "targetHandle": "conversationalAgent_0-input-model-BaseLanguageModel", + "targetHandle": "conversationalAgent_0-input-model-BaseChatModel", "type": "buttonedge", - "id": "chatOpenAI_3-chatOpenAI_3-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalAgent_0-conversationalAgent_0-input-model-BaseLanguageModel", + "id": "chatOpenAI_3-chatOpenAI_3-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalAgent_0-conversationalAgent_0-input-model-BaseChatModel", "data": { "label": "" } diff --git a/packages/server/marketplaces/chatflows/Conversational Agent.json b/packages/server/marketplaces/chatflows/Conversational Agent.json index 2232ade0..8994594a 100644 --- a/packages/server/marketplaces/chatflows/Conversational Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Agent.json @@ -13,8 +13,8 @@ "data": { "id": "calculator_1", "label": "Calculator", - "name": "calculator", "version": 1, + "name": "calculator", "type": "Calculator", "baseClasses": ["Calculator", "Tool", "StructuredTool", "BaseLangChain"], "category": "Tools", @@ -52,8 +52,8 @@ "data": { "id": "bufferMemory_1", "label": "Buffer Memory", - "name": "bufferMemory", "version": 1, + "name": "bufferMemory", "type": "BufferMemory", "baseClasses": ["BufferMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", @@ -109,8 +109,8 @@ "data": { "id": "serpAPI_0", "label": "Serp API", - "name": "serpAPI", "version": 1, + "name": "serpAPI", "type": "SerpAPI", "baseClasses": ["SerpAPI", "Tool", "StructuredTool"], "category": "Tools", @@ -146,7 +146,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_0", "position": { "x": 97.01321406237057, @@ -156,8 +156,8 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -287,7 +287,7 @@ } ], "inputs": { - "modelName": "gpt-3.5-turbo", + "modelName": "gpt-3.5-turbo-16k", "temperature": 0.9, "maxTokens": "", "topP": "", @@ -320,17 +320,17 @@ "height": 383, "id": "conversationalAgent_0", "position": { - "x": 1164.4550359451973, - "y": 283.40041124403075 + "x": 1191.1524476753796, + "y": 324.2479396683294 }, "type": "customNode", "data": { "id": "conversationalAgent_0", "label": "Conversational Agent", + "version": 2, "name": "conversationalAgent", - "version": 1, "type": "AgentExecutor", - "baseClasses": ["AgentExecutor", "BaseChain"], + "baseClasses": ["AgentExecutor", "BaseChain", "Runnable"], "category": "Agents", "description": "Conversational agent for a chat model. It will utilize chat specific prompts", "inputParams": [ @@ -356,8 +356,8 @@ { "label": "Language Model", "name": "model", - "type": "BaseLanguageModel", - "id": "conversationalAgent_0-input-model-BaseLanguageModel" + "type": "BaseChatModel", + "id": "conversationalAgent_0-input-model-BaseChatModel" }, { "label": "Memory", @@ -374,10 +374,10 @@ }, "outputAnchors": [ { - "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain", + "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain|Runnable", "name": "conversationalAgent", "label": "AgentExecutor", - "type": "AgentExecutor | BaseChain" + "type": "AgentExecutor | BaseChain | Runnable" } ], "outputs": {}, @@ -385,8 +385,8 @@ }, "selected": false, "positionAbsolute": { - "x": 1164.4550359451973, - "y": 283.40041124403075 + "x": 1191.1524476753796, + "y": 324.2479396683294 }, "dragging": false } @@ -418,9 +418,9 @@ "source": "chatOpenAI_0", "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", "target": "conversationalAgent_0", - "targetHandle": "conversationalAgent_0-input-model-BaseLanguageModel", + "targetHandle": "conversationalAgent_0-input-model-BaseChatModel", "type": "buttonedge", - "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalAgent_0-conversationalAgent_0-input-model-BaseLanguageModel", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalAgent_0-conversationalAgent_0-input-model-BaseChatModel", "data": { "label": "" } diff --git a/packages/server/marketplaces/chatflows/Multiple VectorDB.json b/packages/server/marketplaces/chatflows/Multiple VectorDB.json index e7718616..789b0c08 100644 --- a/packages/server/marketplaces/chatflows/Multiple VectorDB.json +++ b/packages/server/marketplaces/chatflows/Multiple VectorDB.json @@ -1127,81 +1127,6 @@ }, "dragging": false }, - { - "width": 300, - "height": 383, - "id": "conversationalAgent_0", - "position": { - "x": 2506.011817109287, - "y": -241.58006840004734 - }, - "type": "customNode", - "data": { - "id": "conversationalAgent_0", - "label": "Conversational Agent", - "version": 1, - "name": "conversationalAgent", - "type": "AgentExecutor", - "baseClasses": ["AgentExecutor", "BaseChain", "Runnable"], - "category": "Agents", - "description": "Conversational agent for a chat model. It will utilize chat specific prompts", - "inputParams": [ - { - "label": "System Message", - "name": "systemMessage", - "type": "string", - "rows": 4, - "default": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.", - "optional": true, - "additionalParams": true, - "id": "conversationalAgent_0-input-systemMessage-string" - } - ], - "inputAnchors": [ - { - "label": "Allowed Tools", - "name": "tools", - "type": "Tool", - "list": true, - "id": "conversationalAgent_0-input-tools-Tool" - }, - { - "label": "Language Model", - "name": "model", - "type": "BaseLanguageModel", - "id": "conversationalAgent_0-input-model-BaseLanguageModel" - }, - { - "label": "Memory", - "name": "memory", - "type": "BaseChatMemory", - "id": "conversationalAgent_0-input-memory-BaseChatMemory" - } - ], - "inputs": { - "tools": ["{{chainTool_2.data.instance}}", "{{chainTool_3.data.instance}}"], - "model": "{{chatOpenAI_2.data.instance}}", - "memory": "{{bufferMemory_0.data.instance}}", - "systemMessage": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist." - }, - "outputAnchors": [ - { - "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain|Runnable", - "name": "conversationalAgent", - "label": "AgentExecutor", - "type": "AgentExecutor | BaseChain | Runnable" - } - ], - "outputs": {}, - "selected": false - }, - "selected": false, - "positionAbsolute": { - "x": 2506.011817109287, - "y": -241.58006840004734 - }, - "dragging": false - }, { "width": 300, "height": 574, @@ -1602,6 +1527,81 @@ "y": 75.96855802341503 }, "dragging": false + }, + { + "width": 300, + "height": 383, + "id": "conversationalAgent_0", + "position": { + "x": 2432.125364763489, + "y": -105.27942167533908 + }, + "type": "customNode", + "data": { + "id": "conversationalAgent_0", + "label": "Conversational Agent", + "version": 2, + "name": "conversationalAgent", + "type": "AgentExecutor", + "baseClasses": ["AgentExecutor", "BaseChain", "Runnable"], + "category": "Agents", + "description": "Conversational agent for a chat model. It will utilize chat specific prompts", + "inputParams": [ + { + "label": "System Message", + "name": "systemMessage", + "type": "string", + "rows": 4, + "default": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.", + "optional": true, + "additionalParams": true, + "id": "conversationalAgent_0-input-systemMessage-string" + } + ], + "inputAnchors": [ + { + "label": "Allowed Tools", + "name": "tools", + "type": "Tool", + "list": true, + "id": "conversationalAgent_0-input-tools-Tool" + }, + { + "label": "Language Model", + "name": "model", + "type": "BaseChatModel", + "id": "conversationalAgent_0-input-model-BaseChatModel" + }, + { + "label": "Memory", + "name": "memory", + "type": "BaseChatMemory", + "id": "conversationalAgent_0-input-memory-BaseChatMemory" + } + ], + "inputs": { + "tools": ["{{chainTool_2.data.instance}}", "{{chainTool_3.data.instance}}"], + "model": "{{chatOpenAI_2.data.instance}}", + "memory": "{{bufferMemory_0.data.instance}}", + "systemMessage": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist." + }, + "outputAnchors": [ + { + "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain|Runnable", + "name": "conversationalAgent", + "label": "AgentExecutor", + "type": "AgentExecutor | BaseChain | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 2432.125364763489, + "y": -105.27942167533908 + }, + "dragging": false } ], "edges": [ @@ -1704,6 +1704,28 @@ "label": "" } }, + { + "source": "plainText_1", + "sourceHandle": "plainText_1-output-document-Document", + "target": "faiss_0", + "targetHandle": "faiss_0-input-document-Document", + "type": "buttonedge", + "id": "plainText_1-plainText_1-output-document-Document-faiss_0-faiss_0-input-document-Document", + "data": { + "label": "" + } + }, + { + "source": "recursiveCharacterTextSplitter_0", + "sourceHandle": "recursiveCharacterTextSplitter_0-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable", + "target": "plainText_1", + "targetHandle": "plainText_1-input-textSplitter-TextSplitter", + "type": "buttonedge", + "id": "recursiveCharacterTextSplitter_0-recursiveCharacterTextSplitter_0-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable-plainText_1-plainText_1-input-textSplitter-TextSplitter", + "data": { + "label": "" + } + }, { "source": "chainTool_2", "sourceHandle": "chainTool_2-output-chainTool-ChainTool|DynamicTool|Tool|StructuredTool|BaseLangChain", @@ -1730,9 +1752,9 @@ "source": "chatOpenAI_2", "sourceHandle": "chatOpenAI_2-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", "target": "conversationalAgent_0", - "targetHandle": "conversationalAgent_0-input-model-BaseLanguageModel", + "targetHandle": "conversationalAgent_0-input-model-BaseChatModel", "type": "buttonedge", - "id": "chatOpenAI_2-chatOpenAI_2-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-conversationalAgent_0-conversationalAgent_0-input-model-BaseLanguageModel", + "id": "chatOpenAI_2-chatOpenAI_2-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-conversationalAgent_0-conversationalAgent_0-input-model-BaseChatModel", "data": { "label": "" } @@ -1747,28 +1769,6 @@ "data": { "label": "" } - }, - { - "source": "plainText_1", - "sourceHandle": "plainText_1-output-document-Document", - "target": "faiss_0", - "targetHandle": "faiss_0-input-document-Document", - "type": "buttonedge", - "id": "plainText_1-plainText_1-output-document-Document-faiss_0-faiss_0-input-document-Document", - "data": { - "label": "" - } - }, - { - "source": "recursiveCharacterTextSplitter_0", - "sourceHandle": "recursiveCharacterTextSplitter_0-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable", - "target": "plainText_1", - "targetHandle": "plainText_1-input-textSplitter-TextSplitter", - "type": "buttonedge", - "id": "recursiveCharacterTextSplitter_0-recursiveCharacterTextSplitter_0-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable-plainText_1-plainText_1-input-textSplitter-TextSplitter", - "data": { - "label": "" - } } ] } diff --git a/packages/server/marketplaces/chatflows/OpenAI Agent.json b/packages/server/marketplaces/chatflows/OpenAI Agent.json index 931bae0c..0cb3c3b3 100644 --- a/packages/server/marketplaces/chatflows/OpenAI Agent.json +++ b/packages/server/marketplaces/chatflows/OpenAI Agent.json @@ -13,8 +13,8 @@ "data": { "id": "calculator_0", "label": "Calculator", - "name": "calculator", "version": 1, + "name": "calculator", "type": "Calculator", "baseClasses": ["Calculator", "Tool", "StructuredTool", "BaseLangChain", "Serializable"], "category": "Tools", @@ -52,8 +52,8 @@ "data": { "id": "bufferMemory_0", "label": "Buffer Memory", - "name": "bufferMemory", "version": 1, + "name": "bufferMemory", "type": "BufferMemory", "baseClasses": ["BufferMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", @@ -109,8 +109,8 @@ "data": { "id": "customTool_0", "label": "Custom Tool", - "name": "customTool", "version": 1, + "name": "customTool", "type": "CustomTool", "baseClasses": ["CustomTool", "Tool", "StructuredTool"], "category": "Tools", @@ -158,8 +158,8 @@ "data": { "id": "serper_0", "label": "Serper", - "name": "serper", "version": 1, + "name": "serper", "type": "Serper", "baseClasses": ["Serper", "Tool", "StructuredTool"], "category": "Tools", @@ -269,7 +269,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_0", "position": { "x": 817.8210275868742, @@ -279,8 +279,8 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -473,17 +473,6 @@ "label": "" } }, - { - "source": "chatOpenAI_0", - "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", - "target": "openAIFunctionAgent_0", - "targetHandle": "openAIFunctionAgent_0-input-model-BaseChatModel", - "type": "buttonedge", - "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-openAIFunctionAgent_0-openAIFunctionAgent_0-input-model-BaseChatModel", - "data": { - "label": "" - } - }, { "source": "bufferMemory_0", "sourceHandle": "bufferMemory_0-output-bufferMemory-BufferMemory|BaseChatMemory|BaseMemory", @@ -494,6 +483,17 @@ "data": { "label": "" } + }, + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", + "target": "openAIFunctionAgent_0", + "targetHandle": "openAIFunctionAgent_0-input-model-ChatOpenAI | AzureChatOpenAI", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-openAIFunctionAgent_0-openAIFunctionAgent_0-input-model-ChatOpenAI | AzureChatOpenAI", + "data": { + "label": "" + } } ] } diff --git a/packages/server/marketplaces/chatflows/OpenAI Assistant.json b/packages/server/marketplaces/chatflows/OpenAI Assistant.json index 2f9a860c..ba4c6134 100644 --- a/packages/server/marketplaces/chatflows/OpenAI Assistant.json +++ b/packages/server/marketplaces/chatflows/OpenAI Assistant.json @@ -14,7 +14,7 @@ "data": { "id": "openAIAssistant_0", "label": "OpenAI Assistant", - "version": 1, + "version": 2, "name": "openAIAssistant", "type": "OpenAIAssistant", "baseClasses": ["OpenAIAssistant"], @@ -27,6 +27,15 @@ "type": "asyncOptions", "loadMethod": "listAssistants", "id": "openAIAssistant_0-input-selectedAssistant-asyncOptions" + }, + { + "label": "Disable File Download", + "name": "disableFileDownload", + "type": "boolean", + "description": "Messages can contain text, images, or files. In some cases, you may want to prevent others from downloading the files. Learn more from OpenAI File Annotation docs", + "optional": true, + "additionalParams": true, + "id": "openAIAssistant_0-input-disableFileDownload-boolean" } ], "inputAnchors": [ diff --git a/packages/server/marketplaces/chatflows/WebBrowser.json b/packages/server/marketplaces/chatflows/WebBrowser.json index 2f6fb721..0547366a 100644 --- a/packages/server/marketplaces/chatflows/WebBrowser.json +++ b/packages/server/marketplaces/chatflows/WebBrowser.json @@ -13,8 +13,8 @@ "data": { "id": "bufferMemory_0", "label": "Buffer Memory", - "name": "bufferMemory", "version": 1, + "name": "bufferMemory", "type": "BufferMemory", "baseClasses": ["BufferMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", @@ -70,8 +70,8 @@ "data": { "id": "webBrowser_0", "label": "Web Browser", - "name": "webBrowser", "version": 1, + "name": "webBrowser", "type": "WebBrowser", "baseClasses": ["WebBrowser", "Tool", "StructuredTool", "BaseLangChain"], "category": "Tools", @@ -115,82 +115,7 @@ }, { "width": 300, - "height": 383, - "id": "conversationalAgent_0", - "position": { - "x": 1464.513303631911, - "y": 155.73036805253955 - }, - "type": "customNode", - "data": { - "id": "conversationalAgent_0", - "label": "Conversational Agent", - "name": "conversationalAgent", - "version": 1, - "type": "AgentExecutor", - "baseClasses": ["AgentExecutor", "BaseChain"], - "category": "Agents", - "description": "Conversational agent for a chat model. It will utilize chat specific prompts", - "inputParams": [ - { - "label": "System Message", - "name": "systemMessage", - "type": "string", - "rows": 4, - "default": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.", - "optional": true, - "additionalParams": true, - "id": "conversationalAgent_0-input-systemMessage-string" - } - ], - "inputAnchors": [ - { - "label": "Allowed Tools", - "name": "tools", - "type": "Tool", - "list": true, - "id": "conversationalAgent_0-input-tools-Tool" - }, - { - "label": "Language Model", - "name": "model", - "type": "BaseLanguageModel", - "id": "conversationalAgent_0-input-model-BaseLanguageModel" - }, - { - "label": "Memory", - "name": "memory", - "type": "BaseChatMemory", - "id": "conversationalAgent_0-input-memory-BaseChatMemory" - } - ], - "inputs": { - "tools": ["{{webBrowser_0.data.instance}}"], - "model": "{{chatOpenAI_1.data.instance}}", - "memory": "{{bufferMemory_0.data.instance}}", - "systemMessage": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist." - }, - "outputAnchors": [ - { - "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain", - "name": "conversationalAgent", - "label": "AgentExecutor", - "type": "AgentExecutor | BaseChain" - } - ], - "outputs": {}, - "selected": false - }, - "selected": false, - "positionAbsolute": { - "x": 1464.513303631911, - "y": 155.73036805253955 - }, - "dragging": false - }, - { - "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_0", "position": { "x": 734.7477982032904, @@ -200,8 +125,8 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -371,8 +296,8 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "name": "openAIEmbeddings", "version": 1, + "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], "category": "Embeddings", @@ -445,7 +370,7 @@ }, { "width": 300, - "height": 523, + "height": 574, "id": "chatOpenAI_1", "position": { "x": 68.312124033115, @@ -455,8 +380,8 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "name": "chatOpenAI", "version": 2, + "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -586,7 +511,7 @@ } ], "inputs": { - "modelName": "gpt-3.5-turbo", + "modelName": "gpt-3.5-turbo-16k", "temperature": 0.9, "maxTokens": "", "topP": "", @@ -613,6 +538,81 @@ "y": -239.65476709991256 }, "dragging": false + }, + { + "width": 300, + "height": 383, + "id": "conversationalAgent_0", + "position": { + "x": 1518.944765840293, + "y": 212.2513364217197 + }, + "type": "customNode", + "data": { + "id": "conversationalAgent_0", + "label": "Conversational Agent", + "version": 2, + "name": "conversationalAgent", + "type": "AgentExecutor", + "baseClasses": ["AgentExecutor", "BaseChain", "Runnable"], + "category": "Agents", + "description": "Conversational agent for a chat model. It will utilize chat specific prompts", + "inputParams": [ + { + "label": "System Message", + "name": "systemMessage", + "type": "string", + "rows": 4, + "default": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.", + "optional": true, + "additionalParams": true, + "id": "conversationalAgent_0-input-systemMessage-string" + } + ], + "inputAnchors": [ + { + "label": "Allowed Tools", + "name": "tools", + "type": "Tool", + "list": true, + "id": "conversationalAgent_0-input-tools-Tool" + }, + { + "label": "Language Model", + "name": "model", + "type": "BaseChatModel", + "id": "conversationalAgent_0-input-model-BaseChatModel" + }, + { + "label": "Memory", + "name": "memory", + "type": "BaseChatMemory", + "id": "conversationalAgent_0-input-memory-BaseChatMemory" + } + ], + "inputs": { + "tools": ["{{webBrowser_0.data.instance}}"], + "model": "{{chatOpenAI_1.data.instance}}", + "memory": "{{bufferMemory_0.data.instance}}", + "systemMessage": "Assistant is a large language model trained by OpenAI.\n\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\n\nOverall, Assistant is a powerful system that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist." + }, + "outputAnchors": [ + { + "id": "conversationalAgent_0-output-conversationalAgent-AgentExecutor|BaseChain|Runnable", + "name": "conversationalAgent", + "label": "AgentExecutor", + "type": "AgentExecutor | BaseChain | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1518.944765840293, + "y": 212.2513364217197 + }, + "dragging": false } ], "edges": [ @@ -638,17 +638,6 @@ "label": "" } }, - { - "source": "chatOpenAI_1", - "sourceHandle": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", - "target": "conversationalAgent_0", - "targetHandle": "conversationalAgent_0-input-model-BaseLanguageModel", - "type": "buttonedge", - "id": "chatOpenAI_1-chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalAgent_0-conversationalAgent_0-input-model-BaseLanguageModel", - "data": { - "label": "" - } - }, { "source": "webBrowser_0", "sourceHandle": "webBrowser_0-output-webBrowser-WebBrowser|Tool|StructuredTool|BaseLangChain", @@ -660,6 +649,17 @@ "label": "" } }, + { + "source": "chatOpenAI_1", + "sourceHandle": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", + "target": "conversationalAgent_0", + "targetHandle": "conversationalAgent_0-input-model-BaseChatModel", + "type": "buttonedge", + "id": "chatOpenAI_1-chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalAgent_0-conversationalAgent_0-input-model-BaseChatModel", + "data": { + "label": "" + } + }, { "source": "bufferMemory_0", "sourceHandle": "bufferMemory_0-output-bufferMemory-BufferMemory|BaseChatMemory|BaseMemory", diff --git a/packages/server/package.json b/packages/server/package.json index 3503e982..6f4ccaf4 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.4.2", + "version": "1.4.3", "description": "Flowiseai Server", "main": "dist/index", "types": "dist/index.d.ts", diff --git a/packages/server/src/Interface.ts b/packages/server/src/Interface.ts index c562b4ee..d5890ab6 100644 --- a/packages/server/src/Interface.ts +++ b/packages/server/src/Interface.ts @@ -190,12 +190,6 @@ export interface IOverrideConfig { type: string } -export interface IDatabaseExport { - chatmessages: IChatMessage[] - chatflows: IChatFlow[] - apikeys: ICommonObject[] -} - export type ICredentialDataDecrypted = ICommonObject // Plain credential object sent to server diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 91de4f4c..1ebd9312 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -17,7 +17,6 @@ import { IReactFlowNode, IReactFlowObject, INodeData, - IDatabaseExport, ICredentialReturnResponse, chatType, IChatMessage, @@ -31,18 +30,11 @@ import { constructGraphs, resolveVariables, isStartNodeDependOnInput, - getAPIKeys, - addAPIKey, - updateAPIKey, - deleteAPIKey, - compareKeys, mapMimeTypeToInputField, findAvailableConfigs, isSameOverrideConfig, - replaceAllAPIKeys, isFlowValidForStream, databaseEntities, - getApiKey, transformToCredentialEntity, decryptCredentialData, clearAllSessionMemory, @@ -64,6 +56,7 @@ import { ChatflowPool } from './ChatflowPool' import { CachePool } from './CachePool' import { ICommonObject, INodeOptionsValue } from 'flowise-components' import { createRateLimiter, getRateLimiter, initializeRateLimiter } from './utils/rateLimit' +import { addAPIKey, compareKeys, deleteAPIKey, getApiKey, getAPIKeys, updateAPIKey } from './utils/apiKey' export class App { app: express.Application @@ -1025,57 +1018,6 @@ export class App { } }) - // ---------------------------------------- - // Export Load Chatflow & ChatMessage & Apikeys - // ---------------------------------------- - - this.app.get('/api/v1/database/export', async (req: Request, res: Response) => { - const chatmessages = await this.AppDataSource.getRepository(ChatMessage).find() - const chatflows = await this.AppDataSource.getRepository(ChatFlow).find() - const apikeys = await getAPIKeys() - const result: IDatabaseExport = { - chatmessages, - chatflows, - apikeys - } - return res.json(result) - }) - - this.app.post('/api/v1/database/load', async (req: Request, res: Response) => { - const databaseItems: IDatabaseExport = req.body - - await this.AppDataSource.getRepository(ChatFlow).delete({}) - await this.AppDataSource.getRepository(ChatMessage).delete({}) - - let error = '' - - // Get a new query runner instance - const queryRunner = this.AppDataSource.createQueryRunner() - - // Start a new transaction - await queryRunner.startTransaction() - - try { - const chatflows: ChatFlow[] = databaseItems.chatflows - const chatmessages: ChatMessage[] = databaseItems.chatmessages - - await queryRunner.manager.insert(ChatFlow, chatflows) - await queryRunner.manager.insert(ChatMessage, chatmessages) - - await queryRunner.commitTransaction() - } catch (err: any) { - error = err?.message ?? 'Error loading database' - await queryRunner.rollbackTransaction() - } finally { - await queryRunner.release() - } - - await replaceAllAPIKeys(databaseItems.apikeys) - - if (error) return res.status(500).send(error) - return res.status(201).send('OK') - }) - // ---------------------------------------- // Upsert // ---------------------------------------- diff --git a/packages/server/src/utils/apiKey.ts b/packages/server/src/utils/apiKey.ts new file mode 100644 index 00000000..08a9ecd3 --- /dev/null +++ b/packages/server/src/utils/apiKey.ts @@ -0,0 +1,147 @@ +import { randomBytes, scryptSync, timingSafeEqual } from 'crypto' +import { ICommonObject } from 'flowise-components' +import moment from 'moment' +import fs from 'fs' +import path from 'path' +import logger from './logger' + +/** + * Returns the api key path + * @returns {string} + */ +export const getAPIKeyPath = (): string => { + return process.env.APIKEY_PATH ? path.join(process.env.APIKEY_PATH, 'api.json') : path.join(__dirname, '..', '..', 'api.json') +} + +/** + * Generate the api key + * @returns {string} + */ +export const generateAPIKey = (): string => { + const buffer = randomBytes(32) + return buffer.toString('base64') +} + +/** + * Generate the secret key + * @param {string} apiKey + * @returns {string} + */ +export const generateSecretHash = (apiKey: string): string => { + const salt = randomBytes(8).toString('hex') + const buffer = scryptSync(apiKey, salt, 64) as Buffer + return `${buffer.toString('hex')}.${salt}` +} + +/** + * Verify valid keys + * @param {string} storedKey + * @param {string} suppliedKey + * @returns {boolean} + */ +export const compareKeys = (storedKey: string, suppliedKey: string): boolean => { + const [hashedPassword, salt] = storedKey.split('.') + const buffer = scryptSync(suppliedKey, salt, 64) as Buffer + return timingSafeEqual(Buffer.from(hashedPassword, 'hex'), buffer) +} + +/** + * Get API keys + * @returns {Promise} + */ +export const getAPIKeys = async (): Promise => { + try { + const content = await fs.promises.readFile(getAPIKeyPath(), 'utf8') + return JSON.parse(content) + } catch (error) { + const keyName = 'DefaultKey' + const apiKey = generateAPIKey() + const apiSecret = generateSecretHash(apiKey) + const content = [ + { + keyName, + apiKey, + apiSecret, + createdAt: moment().format('DD-MMM-YY'), + id: randomBytes(16).toString('hex') + } + ] + await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8') + return content + } +} + +/** + * Add new API key + * @param {string} keyName + * @returns {Promise} + */ +export const addAPIKey = async (keyName: string): Promise => { + const existingAPIKeys = await getAPIKeys() + const apiKey = generateAPIKey() + const apiSecret = generateSecretHash(apiKey) + const content = [ + ...existingAPIKeys, + { + keyName, + apiKey, + apiSecret, + createdAt: moment().format('DD-MMM-YY'), + id: randomBytes(16).toString('hex') + } + ] + await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8') + return content +} + +/** + * Get API Key details + * @param {string} apiKey + * @returns {Promise} + */ +export const getApiKey = async (apiKey: string) => { + const existingAPIKeys = await getAPIKeys() + const keyIndex = existingAPIKeys.findIndex((key) => key.apiKey === apiKey) + if (keyIndex < 0) return undefined + return existingAPIKeys[keyIndex] +} + +/** + * Update existing API key + * @param {string} keyIdToUpdate + * @param {string} newKeyName + * @returns {Promise} + */ +export const updateAPIKey = async (keyIdToUpdate: string, newKeyName: string): Promise => { + const existingAPIKeys = await getAPIKeys() + const keyIndex = existingAPIKeys.findIndex((key) => key.id === keyIdToUpdate) + if (keyIndex < 0) return [] + existingAPIKeys[keyIndex].keyName = newKeyName + await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(existingAPIKeys), 'utf8') + return existingAPIKeys +} + +/** + * Delete API key + * @param {string} keyIdToDelete + * @returns {Promise} + */ +export const deleteAPIKey = async (keyIdToDelete: string): Promise => { + const existingAPIKeys = await getAPIKeys() + const result = existingAPIKeys.filter((key) => key.id !== keyIdToDelete) + await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(result), 'utf8') + return result +} + +/** + * Replace all api keys + * @param {ICommonObject[]} content + * @returns {Promise} + */ +export const replaceAllAPIKeys = async (content: ICommonObject[]): Promise => { + try { + await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8') + } catch (error) { + logger.error(error) + } +} diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 86d626c4..423d32af 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -1,33 +1,32 @@ import path from 'path' import fs from 'fs' -import moment from 'moment' import logger from './logger' import { + IComponentCredentials, IComponentNodes, + ICredentialDataDecrypted, + ICredentialReqBody, IDepthQueue, IExploredNode, + INodeData, INodeDependencies, INodeDirectedGraph, INodeQueue, + IOverrideConfig, IReactFlowEdge, IReactFlowNode, - IVariableDict, - INodeData, - IOverrideConfig, - ICredentialDataDecrypted, - IComponentCredentials, - ICredentialReqBody + IVariableDict } from '../Interface' import { cloneDeep, get, isEqual } from 'lodash' import { - ICommonObject, + convertChatHistoryToText, getInputVariables, - IDatabaseEntity, handleEscapeCharacters, - IMessage, - convertChatHistoryToText + ICommonObject, + IDatabaseEntity, + IMessage } from 'flowise-components' -import { scryptSync, randomBytes, timingSafeEqual } from 'crypto' +import { randomBytes } from 'crypto' import { AES, enc } from 'crypto-js' import { ChatFlow } from '../database/entities/ChatFlow' @@ -593,147 +592,6 @@ export const isSameOverrideConfig = ( return false } -/** - * Returns the api key path - * @returns {string} - */ -export const getAPIKeyPath = (): string => { - return process.env.APIKEY_PATH ? path.join(process.env.APIKEY_PATH, 'api.json') : path.join(__dirname, '..', '..', 'api.json') -} - -/** - * Generate the api key - * @returns {string} - */ -export const generateAPIKey = (): string => { - const buffer = randomBytes(32) - return buffer.toString('base64') -} - -/** - * Generate the secret key - * @param {string} apiKey - * @returns {string} - */ -export const generateSecretHash = (apiKey: string): string => { - const salt = randomBytes(8).toString('hex') - const buffer = scryptSync(apiKey, salt, 64) as Buffer - return `${buffer.toString('hex')}.${salt}` -} - -/** - * Verify valid keys - * @param {string} storedKey - * @param {string} suppliedKey - * @returns {boolean} - */ -export const compareKeys = (storedKey: string, suppliedKey: string): boolean => { - const [hashedPassword, salt] = storedKey.split('.') - const buffer = scryptSync(suppliedKey, salt, 64) as Buffer - return timingSafeEqual(Buffer.from(hashedPassword, 'hex'), buffer) -} - -/** - * Get API keys - * @returns {Promise} - */ -export const getAPIKeys = async (): Promise => { - try { - const content = await fs.promises.readFile(getAPIKeyPath(), 'utf8') - return JSON.parse(content) - } catch (error) { - const keyName = 'DefaultKey' - const apiKey = generateAPIKey() - const apiSecret = generateSecretHash(apiKey) - const content = [ - { - keyName, - apiKey, - apiSecret, - createdAt: moment().format('DD-MMM-YY'), - id: randomBytes(16).toString('hex') - } - ] - await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8') - return content - } -} - -/** - * Add new API key - * @param {string} keyName - * @returns {Promise} - */ -export const addAPIKey = async (keyName: string): Promise => { - const existingAPIKeys = await getAPIKeys() - const apiKey = generateAPIKey() - const apiSecret = generateSecretHash(apiKey) - const content = [ - ...existingAPIKeys, - { - keyName, - apiKey, - apiSecret, - createdAt: moment().format('DD-MMM-YY'), - id: randomBytes(16).toString('hex') - } - ] - await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8') - return content -} - -/** - * Get API Key details - * @param {string} apiKey - * @returns {Promise} - */ -export const getApiKey = async (apiKey: string) => { - const existingAPIKeys = await getAPIKeys() - const keyIndex = existingAPIKeys.findIndex((key) => key.apiKey === apiKey) - if (keyIndex < 0) return undefined - return existingAPIKeys[keyIndex] -} - -/** - * Update existing API key - * @param {string} keyIdToUpdate - * @param {string} newKeyName - * @returns {Promise} - */ -export const updateAPIKey = async (keyIdToUpdate: string, newKeyName: string): Promise => { - const existingAPIKeys = await getAPIKeys() - const keyIndex = existingAPIKeys.findIndex((key) => key.id === keyIdToUpdate) - if (keyIndex < 0) return [] - existingAPIKeys[keyIndex].keyName = newKeyName - await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(existingAPIKeys), 'utf8') - return existingAPIKeys -} - -/** - * Delete API key - * @param {string} keyIdToDelete - * @returns {Promise} - */ -export const deleteAPIKey = async (keyIdToDelete: string): Promise => { - const existingAPIKeys = await getAPIKeys() - const result = existingAPIKeys.filter((key) => key.id !== keyIdToDelete) - await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(result), 'utf8') - return result -} - -/** - * Replace all api keys - * @param {ICommonObject[]} content - * @returns {Promise} - */ -export const replaceAllAPIKeys = async (content: ICommonObject[]): Promise => { - try { - await fs.promises.writeFile(getAPIKeyPath(), JSON.stringify(content), 'utf8') - } catch (error) { - logger.error(error) - } -} - /** * Map MimeType to InputField * @param {string} mimeType @@ -844,7 +702,7 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component */ export const isFlowValidForStream = (reactFlowNodes: IReactFlowNode[], endingNodeData: INodeData) => { const streamAvailableLLMs = { - 'Chat Models': ['azureChatOpenAI', 'chatOpenAI', 'chatAnthropic', 'chatOllama'], + 'Chat Models': ['azureChatOpenAI', 'chatOpenAI', 'chatAnthropic', 'chatOllama', 'awsChatBedrock'], LLMs: ['azureOpenAI', 'openAI', 'ollama'] } diff --git a/packages/ui/package.json b/packages/ui/package.json index 6914c04a..76369ab2 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "flowise-ui", - "version": "1.4.0", + "version": "1.4.1", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://flowiseai.com", "author": { diff --git a/packages/ui/src/api/database.js b/packages/ui/src/api/database.js deleted file mode 100644 index f36fb72c..00000000 --- a/packages/ui/src/api/database.js +++ /dev/null @@ -1,9 +0,0 @@ -import client from './client' - -const getExportDatabase = () => client.get('/database/export') -const createLoadDatabase = (body) => client.post('/database/load', body) - -export default { - getExportDatabase, - createLoadDatabase -} diff --git a/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.js b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.js index c10b3289..c2de41b2 100644 --- a/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.js +++ b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.js @@ -1,7 +1,6 @@ import { useState, useRef, useEffect } from 'react' import PropTypes from 'prop-types' -import { useSelector, useDispatch } from 'react-redux' -import { useNavigate } from 'react-router-dom' +import { useSelector } from 'react-redux' // material-ui import { useTheme } from '@mui/material/styles' @@ -26,16 +25,10 @@ import PerfectScrollbar from 'react-perfect-scrollbar' // project imports import MainCard from 'ui-component/cards/MainCard' import Transitions from 'ui-component/extended/Transitions' -import { BackdropLoader } from 'ui-component/loading/BackdropLoader' import AboutDialog from 'ui-component/dialog/AboutDialog' // assets -import { IconLogout, IconSettings, IconFileExport, IconFileDownload, IconInfoCircle } from '@tabler/icons' - -// API -import databaseApi from 'api/database' - -import { SET_MENU } from 'store/actions' +import { IconLogout, IconSettings } from '@tabler/icons' import './index.css' @@ -43,17 +36,13 @@ import './index.css' const ProfileSection = ({ username, handleLogout }) => { const theme = useTheme() - const dispatch = useDispatch() - const navigate = useNavigate() const customization = useSelector((state) => state.customization) const [open, setOpen] = useState(false) - const [loading, setLoading] = useState(false) const [aboutDialogOpen, setAboutDialogOpen] = useState(false) const anchorRef = useRef(null) - const uploadRef = useRef(null) const handleClose = (event) => { if (anchorRef.current && anchorRef.current.contains(event.target)) { @@ -66,56 +55,6 @@ const ProfileSection = ({ username, handleLogout }) => { setOpen((prevOpen) => !prevOpen) } - const handleExportDB = async () => { - setOpen(false) - try { - const response = await databaseApi.getExportDatabase() - const exportItems = response.data - let dataStr = JSON.stringify(exportItems, null, 2) - let dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr) - - let exportFileDefaultName = `DB.json` - - let linkElement = document.createElement('a') - linkElement.setAttribute('href', dataUri) - linkElement.setAttribute('download', exportFileDefaultName) - linkElement.click() - } catch (e) { - console.error(e) - } - } - - const handleFileUpload = (e) => { - if (!e.target.files) return - - const file = e.target.files[0] - const reader = new FileReader() - reader.onload = async (evt) => { - if (!evt?.target?.result) { - return - } - const { result } = evt.target - - if (result.includes(`"chatmessages":[`) && result.includes(`"chatflows":[`) && result.includes(`"apikeys":[`)) { - dispatch({ type: SET_MENU, opened: false }) - setLoading(true) - - try { - await databaseApi.createLoadDatabase(JSON.parse(result)) - setLoading(false) - navigate('/', { replace: true }) - navigate(0) - } catch (e) { - console.error(e) - setLoading(false) - } - } else { - alert('Incorrect Flowise Database Format') - } - } - reader.readAsText(file) - } - const prevOpen = useRef(open) useEffect(() => { if (prevOpen.current === true && open === false) { @@ -196,39 +135,6 @@ const ProfileSection = ({ username, handleLogout }) => { } }} > - { - setOpen(false) - uploadRef.current.click() - }} - > - - - - Load Database} /> - - - - - - Export Database} /> - - { - setOpen(false) - setAboutDialogOpen(true) - }} - > - - - - About Flowise} /> - {localStorage.getItem('username') && localStorage.getItem('password') && ( { )} - handleFileUpload(e)} /> - setAboutDialogOpen(false)} /> ) diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index e3baa2e2..358fc965 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -69,7 +69,9 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) - +