diff --git a/.dockerignore b/.dockerignore index f0083ba105b..3c237853e0d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,3 +5,6 @@ build **/node_modules **/build **/dist + +packages/server/.env +packages/ui/.env diff --git a/.github/workflows/autoSyncMergedPullRequest.yml b/.github/workflows/autoSyncMergedPullRequest.yml index 275520f4b0a..0868c42e70f 100644 --- a/.github/workflows/autoSyncMergedPullRequest.yml +++ b/.github/workflows/autoSyncMergedPullRequest.yml @@ -11,14 +11,14 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Show PR info env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | echo The PR #${{ github.event.pull_request.number }} was merged on main branch! - name: Repository Dispatch - uses: peter-evans/repository-dispatch@v2 + uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.AUTOSYNC_TOKEN }} repository: ${{ secrets.AUTOSYNC_CH_URL }} @@ -28,6 +28,6 @@ jobs: "ref": "${{ github.ref }}", "prNumber": "${{ github.event.pull_request.number }}", "prTitle": "${{ github.event.pull_request.title }}", - "prDescription": "${{ toJSON(github.event.pull_request.description) }}", + "prDescription": "", "sha": "${{ github.sha }}" } diff --git a/.gitignore b/.gitignore index 533f68a5278..99c9f3cdafd 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,60 @@ ## compressed **/*.tgz + +## vscode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +## other keys +*.key +*.keys +*.priv +*.rsa +*.key.json + +## ssh keys +*.ssh +*.ssh-key +.key-mrc + +## Certificate Authority +*.ca + +## Certificate +*.crt + +## Certificate Sign Request +*.csr + +## Certificate +*.der + +## Key database file +*.kdb + +## OSCP request data +*.org + +## PKCS #12 +*.p12 + +## PEM-encoded certificate data +*.pem + +## Random number seed +*.rnd + +## SSLeay data +*.ssleay + +## S/MIME message +*.smime +*.vsix diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55b93e306b1..20c5bab6563 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,7 +44,7 @@ Flowise has 3 different modules in a single mono repository. #### Prerequisite -- Install [PNPM](https://pnpm.io/installation) +- Install [PNPM](https://pnpm.io/installation). The project is configured to use pnpm v9. ```bash npm i -g pnpm ``` diff --git a/docker/.env.example b/docker/.env.example index d685140a94d..8b1e3206546 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -6,8 +6,8 @@ LOG_PATH=/root/.flowise/logs BLOB_STORAGE_PATH=/root/.flowise/storage # NUMBER_OF_PROXIES= 1 -# CORS_ORIGINS="*" -# IFRAME_ORIGINS="*" +# CORS_ORIGINS=* +# IFRAME_ORIGINS=* # DATABASE_TYPE=postgres # DATABASE_PORT=5432 diff --git a/docker/Dockerfile b/docker/Dockerfile index d399f90a296..261ecdaf00c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -4,7 +4,6 @@ USER root RUN apk add --no-cache git RUN apk add --no-cache python3 py3-pip make g++ -RUN apk add --no-cache cmake # needed for pdfjs-dist RUN apk add --no-cache build-base cairo-dev pango-dev @@ -19,4 +18,4 @@ RUN npm install -g flowise WORKDIR /data -CMD "flowise" \ No newline at end of file +CMD "flowise" diff --git a/package.json b/package.json index 680b7effa4b..2cbdeb7231c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.7.1", + "version": "1.7.2", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ diff --git a/packages/components/credentials/ChatflowApi.credential.ts b/packages/components/credentials/ChatflowApi.credential.ts new file mode 100644 index 00000000000..28c4aaec91f --- /dev/null +++ b/packages/components/credentials/ChatflowApi.credential.ts @@ -0,0 +1,23 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class ChatflowApi implements INodeCredential { + label: string + name: string + version: number + inputs: INodeParams[] + + constructor() { + this.label = 'Chatflow API' + this.name = 'chatflowApi' + this.version = 1.0 + this.inputs = [ + { + label: 'Chatflow Api Key', + name: 'chatflowApiKey', + type: 'password' + } + ] + } +} + +module.exports = { credClass: ChatflowApi } diff --git a/packages/components/credentials/E2B.credential.ts b/packages/components/credentials/E2B.credential.ts new file mode 100644 index 00000000000..9228c6cbe8a --- /dev/null +++ b/packages/components/credentials/E2B.credential.ts @@ -0,0 +1,26 @@ +/* +* TODO: Implement codeInterpreter column to chat_message table +import { INodeParams, INodeCredential } from '../src/Interface' + +class E2BApi implements INodeCredential { + label: string + name: string + version: number + inputs: INodeParams[] + + constructor() { + this.label = 'E2B API' + this.name = 'E2BApi' + this.version = 1.0 + this.inputs = [ + { + label: 'E2B Api Key', + name: 'e2bApiKey', + type: 'password' + } + ] + } +} + +module.exports = { credClass: E2BApi } +*/ diff --git a/packages/components/models.json b/packages/components/models.json index 68a41ab0bba..3500cca3b23 100644 --- a/packages/components/models.json +++ b/packages/components/models.json @@ -5,47 +5,68 @@ "models": [ { "label": "anthropic.claude-3-haiku", - "name": "anthropic.claude-3-haiku-20240307-v1:0" + "name": "anthropic.claude-3-haiku-20240307-v1:0", + "description": "Image to text, conversation, chat optimized" }, { "label": "anthropic.claude-3-sonnet", - "name": "anthropic.claude-3-sonnet-20240229-v1:0" + "name": "anthropic.claude-3-sonnet-20240229-v1:0", + "description": "Image to text and code, multilingual conversation, complex reasoning and analysis" + }, + { + "label": "anthropic.claude-3-opus", + "name": "anthropic.claude-3-opus-20240229-v1:0", + "description": "Image to text and code, multilingual conversation, complex reasoning and analysis" }, { "label": "anthropic.claude-instant-v1", - "name": "anthropic.claude-instant-v1" + "name": "anthropic.claude-instant-v1", + "description": "Text generation, conversation" }, { "label": "anthropic.claude-v2:1", - "name": "anthropic.claude-v2:1" + "name": "anthropic.claude-v2:1", + "description": "Text generation, conversation, complex reasoning and analysis" }, { "label": "anthropic.claude-v2", - "name": "anthropic.claude-v2" + "name": "anthropic.claude-v2", + "description": "Text generation, conversation, complex reasoning and analysis" }, { "label": "meta.llama2-13b-chat-v1", - "name": "meta.llama2-13b-chat-v1" + "name": "meta.llama2-13b-chat-v1", + "description": "Text generation, conversation" }, { "label": "meta.llama2-70b-chat-v1", - "name": "meta.llama2-70b-chat-v1" + "name": "meta.llama2-70b-chat-v1", + "description": "Text generation, conversation" }, { "label": "meta.llama3-8b-instruct-v1:0", - "name": "meta.llama3-8b-instruct-v1:0" + "name": "meta.llama3-8b-instruct-v1:0", + "description": "Text summarization, text classification, sentiment analysis" }, { "label": "meta.llama3-70b-instruct-v1:0", - "name": "meta.llama3-70b-instruct-v1:0" + "name": "meta.llama3-70b-instruct-v1:0", + "description": "Language modeling, dialog systems, code generation, text summarization, text classification, sentiment analysis" }, { "label": "mistral.mistral-7b-instruct-v0:2", - "name": "mistral.mistral-7b-instruct-v0:2" + "name": "mistral.mistral-7b-instruct-v0:2", + "description": "Classification, text generation, code generation" }, { "label": "mistral.mixtral-8x7b-instruct-v0:1", - "name": "mistral.mixtral-8x7b-instruct-v0:1" + "name": "mistral.mixtral-8x7b-instruct-v0:1", + "description": "Complex reasoning and analysis, text generation, code generation" + }, + { + "label": "mistral.mistral-large-2402-v1:0", + "name": "mistral.mistral-large-2402-v1:0", + "description": "Complex reasoning and analysis, text generation, code generation, RAG, agents" } ], "regions": [ @@ -309,6 +330,10 @@ { "name": "chatGoogleGenerativeAI", "models": [ + { + "label": "gemini-1.5-flash-latest", + "name": "gemini-1.5-flash-latest" + }, { "label": "gemini-1.5-pro-latest", "name": "gemini-1.5-pro-latest" @@ -335,6 +360,10 @@ { "name": "chatGoogleVertexAI", "models": [ + { + "label": "gemini-1.5-flash", + "name": "gemini-1.5-flash-preview-0514" + }, { "label": "gemini-1.5-pro", "name": "gemini-1.5-pro-preview-0409" @@ -402,6 +431,10 @@ { "name": "chatOpenAI", "models": [ + { + "label": "gpt-4o", + "name": "gpt-4o" + }, { "label": "gpt-4", "name": "gpt-4" @@ -1070,19 +1103,28 @@ "models": [ { "label": "amazon.titan-embed-text-v1", - "name": "amazon.titan-embed-text-v1" + "name": "amazon.titan-embed-text-v1", + "description": "Embedding Dimensions: 1536" + }, + { + "label": "amazon.titan-embed-text-v2", + "name": "amazon.titan-embed-text-v2:0", + "description": "Embedding Dimensions: 1024" }, { "label": "amazon.titan-embed-g1-text-02", - "name": "amazon.titan-embed-g1-text-02" + "name": "amazon.titan-embed-g1-text-02", + "description": "Embedding Dimensions: 1536" }, { "label": "cohere.embed-english-v3", - "name": "cohere.embed-english-v3" + "name": "cohere.embed-english-v3", + "description": "Embedding Dimensions: 1024" }, { "label": "cohere.embed-multilingual-v3", - "name": "cohere.embed-multilingual-v3" + "name": "cohere.embed-multilingual-v3", + "description": "Embedding Dimensions: 1024" } ], "regions": [ diff --git a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts index d8b3d75704e..cddc81f864b 100644 --- a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts +++ b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts @@ -190,6 +190,7 @@ const prepareAgent = async ( const systemMessage = nodeData.inputs?.systemMessage as string const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const inputKey = memory.inputKey ? memory.inputKey : 'input' + const prependMessages = options?.prependMessages const outputParser = ChatConversationalAgent.getDefaultOutputParser({ llm: model, @@ -240,7 +241,7 @@ const prepareAgent = async ( [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, agent_scratchpad: async (i: { input: string; steps: AgentStep[] }) => await constructScratchPad(i.steps), [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { - const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] + const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[] return messages ?? [] } }, diff --git a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts index b7a5ae37190..c6ffeccba53 100644 --- a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts +++ b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts @@ -84,7 +84,7 @@ class ConversationalRetrievalAgent_Agents implements INode { } async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { - return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) } async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { @@ -102,7 +102,7 @@ class ConversationalRetrievalAgent_Agents implements INode { } } - const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) const loggerHandler = new ConsoleCallbackHandler(options.logger) const callbacks = await additionalCallbacks(nodeData, options) @@ -134,7 +134,7 @@ class ConversationalRetrievalAgent_Agents implements INode { } } -const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { +const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const model = nodeData.inputs?.model as ChatOpenAI const memory = nodeData.inputs?.memory as FlowiseMemory const systemMessage = nodeData.inputs?.systemMessage as string @@ -143,6 +143,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId tools = flatten(tools) const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const inputKey = memory.inputKey ? memory.inputKey : 'input' + const prependMessages = options?.prependMessages const prompt = ChatPromptTemplate.fromMessages([ ['ai', systemMessage ? systemMessage : defaultMessage], @@ -160,7 +161,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps), [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { - const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] + const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[] return messages ?? [] } }, diff --git a/packages/components/nodes/agents/MistralAIToolAgent/MistralAIToolAgent.ts b/packages/components/nodes/agents/MistralAIToolAgent/MistralAIToolAgent.ts index 94f9200f053..4999d51a4be 100644 --- a/packages/components/nodes/agents/MistralAIToolAgent/MistralAIToolAgent.ts +++ b/packages/components/nodes/agents/MistralAIToolAgent/MistralAIToolAgent.ts @@ -82,7 +82,7 @@ class MistralAIToolAgent_Agents implements INode { } async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { - return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) } async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { @@ -100,7 +100,7 @@ class MistralAIToolAgent_Agents implements INode { } } - const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) const loggerHandler = new ConsoleCallbackHandler(options.logger) const callbacks = await additionalCallbacks(nodeData, options) @@ -161,7 +161,7 @@ class MistralAIToolAgent_Agents implements INode { } } -const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { +const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const model = nodeData.inputs?.model as ChatOpenAI const memory = nodeData.inputs?.memory as FlowiseMemory const maxIterations = nodeData.inputs?.maxIterations as string @@ -170,6 +170,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId tools = flatten(tools) const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const inputKey = memory.inputKey ? memory.inputKey : 'input' + const prependMessages = options?.prependMessages const prompt = ChatPromptTemplate.fromMessages([ ['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`], @@ -187,7 +188,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps), [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { - const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] + const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[] return messages ?? [] } }, diff --git a/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts b/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts index 7658a83d71d..cbc0da722eb 100644 --- a/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts +++ b/packages/components/nodes/agents/OpenAIAssistant/OpenAIAssistant.ts @@ -8,7 +8,7 @@ import { zodToJsonSchema } from 'zod-to-json-schema' import { AnalyticHandler } from '../../../src/handler' import { Moderation, checkInputs, streamResponse } from '../../moderation/Moderation' import { formatResponse } from '../../outputparsers/OutputParserHelpers' -import { addFileToStorage } from '../../../src/storageUtils' +import { addSingleFileToStorage } from '../../../src/storageUtils' const lenticularBracketRegex = /【[^】]*】/g const imageRegex = /]*\/>/g @@ -731,7 +731,7 @@ const downloadImg = async (openai: OpenAI, fileId: string, fileName: string, ... const image_data_buffer = Buffer.from(image_data) const mime = 'image/png' - await addFileToStorage(mime, image_data_buffer, fileName, ...paths) + await addSingleFileToStorage(mime, image_data_buffer, fileName, ...paths) return image_data_buffer } @@ -754,7 +754,7 @@ const downloadFile = async (openAIApiKey: string, fileObj: any, fileName: string const data_buffer = Buffer.from(data) const mime = 'application/octet-stream' - return await addFileToStorage(mime, data_buffer, fileName, ...paths) + return await addSingleFileToStorage(mime, data_buffer, fileName, ...paths) } catch (error) { console.error('Error downloading or writing the file:', error) return '' diff --git a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts index f3891e23bf3..437102bc4f4 100644 --- a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts +++ b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts @@ -81,7 +81,7 @@ class OpenAIFunctionAgent_Agents implements INode { } async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { - return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) } async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { @@ -99,7 +99,7 @@ class OpenAIFunctionAgent_Agents implements INode { } } - const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) const loggerHandler = new ConsoleCallbackHandler(options.logger) const callbacks = await additionalCallbacks(nodeData, options) @@ -160,7 +160,7 @@ class OpenAIFunctionAgent_Agents implements INode { } } -const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { +const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const model = nodeData.inputs?.model as ChatOpenAI const maxIterations = nodeData.inputs?.maxIterations as string const memory = nodeData.inputs?.memory as FlowiseMemory @@ -169,6 +169,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId tools = flatten(tools) const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const inputKey = memory.inputKey ? memory.inputKey : 'input' + const prependMessages = options?.prependMessages const prompt = ChatPromptTemplate.fromMessages([ ['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`], @@ -186,7 +187,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatAgentSteps(i.steps), [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { - const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] + const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[] return messages ?? [] } }, diff --git a/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent.ts b/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent.ts index 97506fde0d8..a849bfe4b89 100644 --- a/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent.ts +++ b/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent.ts @@ -82,7 +82,7 @@ class OpenAIToolAgent_Agents implements INode { } async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { - return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + return prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) } async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { @@ -100,7 +100,7 @@ class OpenAIToolAgent_Agents implements INode { } } - const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + const executor = prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) const loggerHandler = new ConsoleCallbackHandler(options.logger) const callbacks = await additionalCallbacks(nodeData, options) @@ -161,7 +161,7 @@ class OpenAIToolAgent_Agents implements INode { } } -const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { +const prepareAgent = (nodeData: INodeData, options: ICommonObject, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { const model = nodeData.inputs?.model as ChatOpenAI const maxIterations = nodeData.inputs?.maxIterations as string const memory = nodeData.inputs?.memory as FlowiseMemory @@ -170,6 +170,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId tools = flatten(tools) const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const inputKey = memory.inputKey ? memory.inputKey : 'input' + const prependMessages = options?.prependMessages const prompt = ChatPromptTemplate.fromMessages([ ['system', systemMessage ? systemMessage : `You are a helpful AI assistant.`], @@ -185,7 +186,7 @@ const prepareAgent = (nodeData: INodeData, flowObj: { sessionId?: string; chatId [inputKey]: (i: { input: string; steps: ToolsAgentStep[] }) => i.input, agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(i.steps), [memoryKey]: async (_: { input: string; steps: ToolsAgentStep[] }) => { - const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] + const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[] return messages ?? [] } }, diff --git a/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent_LlamaIndex.ts b/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent_LlamaIndex.ts index 7a33c6d8279..d7ff9ddeb1c 100644 --- a/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent_LlamaIndex.ts +++ b/packages/components/nodes/agents/OpenAIToolAgent/OpenAIToolAgent_LlamaIndex.ts @@ -61,10 +61,12 @@ class OpenAIFunctionAgent_LlamaIndex_Agents implements INode { return null } - async run(nodeData: INodeData, input: string): Promise { + async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { const memory = nodeData.inputs?.memory as FlowiseMemory const model = nodeData.inputs?.model as OpenAI const systemMessage = nodeData.inputs?.systemMessage as string + const prependMessages = options?.prependMessages + let tools = nodeData.inputs?.tools tools = flatten(tools) @@ -77,7 +79,7 @@ class OpenAIFunctionAgent_LlamaIndex_Agents implements INode { }) } - const msgs = (await memory.getChatMessages(this.sessionId, false)) as IMessage[] + const msgs = (await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[] for (const message of msgs) { if (message.type === 'apiMessage') { chatHistory.push({ diff --git a/packages/components/nodes/agents/ReActAgentChat/ReActAgentChat.ts b/packages/components/nodes/agents/ReActAgentChat/ReActAgentChat.ts index ee5629260bf..227f1070675 100644 --- a/packages/components/nodes/agents/ReActAgentChat/ReActAgentChat.ts +++ b/packages/components/nodes/agents/ReActAgentChat/ReActAgentChat.ts @@ -80,6 +80,7 @@ class ReActAgentChat_Agents implements INode { const model = nodeData.inputs?.model as BaseChatModel let tools = nodeData.inputs?.tools as Tool[] const moderations = nodeData.inputs?.inputModeration as Moderation[] + const prependMessages = options?.prependMessages if (moderations && moderations.length > 0) { try { @@ -134,7 +135,7 @@ class ReActAgentChat_Agents implements INode { const callbacks = await additionalCallbacks(nodeData, options) - const chatHistory = ((await memory.getChatMessages(this.sessionId, false)) as IMessage[]) ?? [] + const chatHistory = ((await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[]) ?? [] const chatHistoryString = chatHistory.map((hist) => hist.message).join('\\n') const result = await executor.invoke({ input, chat_history: chatHistoryString }, { callbacks }) diff --git a/packages/components/nodes/agents/ToolAgent/ToolAgent.ts b/packages/components/nodes/agents/ToolAgent/ToolAgent.ts index 6eeeb745d6e..6d7dc03b42b 100644 --- a/packages/components/nodes/agents/ToolAgent/ToolAgent.ts +++ b/packages/components/nodes/agents/ToolAgent/ToolAgent.ts @@ -54,7 +54,7 @@ class ToolAgent_Agents implements INode { name: 'model', type: 'BaseChatModel', description: - 'Only compatible with models that are capable of function calling. ChatOpenAI, ChatMistral, ChatAnthropic, ChatVertexAI' + 'Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat' }, { label: 'System Message', @@ -191,6 +191,7 @@ const prepareAgent = async ( tools = flatten(tools) const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' const inputKey = memory.inputKey ? memory.inputKey : 'input' + const prependMessages = options?.prependMessages const prompt = ChatPromptTemplate.fromMessages([ ['system', systemMessage], @@ -239,7 +240,7 @@ const prepareAgent = async ( [inputKey]: (i: { input: string; steps: ToolsAgentStep[] }) => i.input, agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(i.steps), [memoryKey]: async (_: { input: string; steps: ToolsAgentStep[] }) => { - const messages = (await memory.getChatMessages(flowObj?.sessionId, true)) as BaseMessage[] + const messages = (await memory.getChatMessages(flowObj?.sessionId, true, prependMessages)) as BaseMessage[] return messages ?? [] } }, diff --git a/packages/components/nodes/agents/XMLAgent/XMLAgent.ts b/packages/components/nodes/agents/XMLAgent/XMLAgent.ts index b92d6fd1004..af311fcfbb0 100644 --- a/packages/components/nodes/agents/XMLAgent/XMLAgent.ts +++ b/packages/components/nodes/agents/XMLAgent/XMLAgent.ts @@ -122,7 +122,7 @@ class XMLAgent_Agents implements INode { return formatResponse(e.message) } } - const executor = await prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }) + const executor = await prepareAgent(nodeData, options, { sessionId: this.sessionId, chatId: options.chatId, input }) const loggerHandler = new ConsoleCallbackHandler(options.logger) const callbacks = await additionalCallbacks(nodeData, options) @@ -183,7 +183,11 @@ class XMLAgent_Agents implements INode { } } -const prepareAgent = async (nodeData: INodeData, flowObj: { sessionId?: string; chatId?: string; input?: string }) => { +const prepareAgent = async ( + nodeData: INodeData, + options: ICommonObject, + flowObj: { sessionId?: string; chatId?: string; input?: string } +) => { const model = nodeData.inputs?.model as BaseChatModel const maxIterations = nodeData.inputs?.maxIterations as string const memory = nodeData.inputs?.memory as FlowiseMemory @@ -192,6 +196,7 @@ const prepareAgent = async (nodeData: INodeData, flowObj: { sessionId?: string; tools = flatten(tools) const inputKey = memory.inputKey ? memory.inputKey : 'input' const memoryKey = memory.memoryKey ? memory.memoryKey : 'chat_history' + const prependMessages = options?.prependMessages let promptMessage = systemMessage ? systemMessage : defaultSystemMessage if (memory.memoryKey) promptMessage = promptMessage.replaceAll('{chat_history}', `{${memory.memoryKey}}`) @@ -210,7 +215,7 @@ const prepareAgent = async (nodeData: INodeData, flowObj: { sessionId?: string; const llmWithStop = model.bind({ stop: ['', ''] }) - const messages = (await memory.getChatMessages(flowObj.sessionId, false)) as IMessage[] + const messages = (await memory.getChatMessages(flowObj.sessionId, false, prependMessages)) as IMessage[] let chatHistoryMsgTxt = '' for (const message of messages) { if (message.type === 'apiMessage') { diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index 672ede7b1c8..73dc9c68c71 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -220,6 +220,7 @@ const prepareChain = async (nodeData: INodeData, options: ICommonObject, session let model = nodeData.inputs?.model as BaseChatModel const memory = nodeData.inputs?.memory as FlowiseMemory const memoryKey = memory.memoryKey ?? 'chat_history' + const prependMessages = options?.prependMessages let messageContent: MessageContentImageUrl[] = [] if (llmSupportsVision(model)) { @@ -252,7 +253,7 @@ const prepareChain = async (nodeData: INodeData, options: ICommonObject, session { [inputKey]: (input: { input: string }) => input.input, [memoryKey]: async () => { - const history = await memory.getChatMessages(sessionId, true) + const history = await memory.getChatMessages(sessionId, true, prependMessages) return history }, ...promptVariables diff --git a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts index bb68bc47675..5a0e40685dc 100644 --- a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts +++ b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts @@ -175,6 +175,7 @@ class ConversationalRetrievalQAChain_Chains implements INode { const rephrasePrompt = nodeData.inputs?.rephrasePrompt as string const responsePrompt = nodeData.inputs?.responsePrompt as string const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean + const prependMessages = options?.prependMessages const appDataSource = options.appDataSource as DataSource const databaseEntities = options.databaseEntities as IDatabaseEntity @@ -210,7 +211,7 @@ class ConversationalRetrievalQAChain_Chains implements INode { } const answerChain = createChain(model, vectorStoreRetriever, rephrasePrompt, customResponsePrompt) - const history = ((await memory.getChatMessages(this.sessionId, false)) as IMessage[]) ?? [] + const history = ((await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[]) ?? [] const loggerHandler = new ConsoleCallbackHandler(options.logger) const additionalCallback = await additionalCallbacks(nodeData, options) @@ -401,7 +402,11 @@ class BufferMemory extends FlowiseMemory implements MemoryMethods { this.chatflowid = fields.chatflowid } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { if (!overrideSessionId) return [] const chatMessage = await this.appDataSource.getRepository(this.databaseEntities['ChatMessage']).find({ @@ -414,6 +419,10 @@ class BufferMemory extends FlowiseMemory implements MemoryMethods { } }) + if (prependMessages?.length) { + chatMessage.unshift(...prependMessages) + } + if (returnBaseMessages) { return mapChatMessageToBaseMessage(chatMessage) } diff --git a/packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts b/packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts index 47425ed273c..89981e8710f 100644 --- a/packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts +++ b/packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts @@ -206,7 +206,8 @@ class LangchainChatGoogleGenerativeAI extends BaseChatModel implements GoogleGen options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun ): Promise { - const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel) + let prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel) + prompt = checkIfEmptyContentAndSameRole(prompt) // Handle streaming if (this.streaming) { @@ -235,7 +236,9 @@ class LangchainChatGoogleGenerativeAI extends BaseChatModel implements GoogleGen options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun ): AsyncGenerator { - const prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel) + let prompt = convertBaseMessagesToContent(messages, this._isMultimodalModel) + prompt = checkIfEmptyContentAndSameRole(prompt) + //@ts-ignore if (options.tools !== undefined && options.tools.length > 0) { const result = await this._generateNonStreaming(prompt, options, runManager) @@ -333,7 +336,9 @@ function convertAuthorToRole(author: string) { case 'tool': return 'function' default: - throw new Error(`Unknown / unsupported author: ${author}`) + // Instead of throwing, we return model + // throw new Error(`Unknown / unsupported author: ${author}`) + return 'model' } } @@ -396,6 +401,25 @@ function convertMessageContentToParts(content: MessageContent, isMultimodalModel }) } +/* + * This is a dedicated logic for Multi Agent Supervisor to handle the case where the content is empty, and the role is the same + */ + +function checkIfEmptyContentAndSameRole(contents: Content[]) { + let prevRole = '' + const removedContents: Content[] = [] + for (const content of contents) { + const role = content.role + if (content.parts.length && content.parts[0].text === '' && role === prevRole) { + removedContents.push(content) + } + + prevRole = role + } + + return contents.filter((content) => !removedContents.includes(content)) +} + function convertBaseMessagesToContent(messages: BaseMessage[], isMultimodalModel: boolean) { return messages.reduce<{ content: Content[] diff --git a/packages/components/nodes/chatmodels/ChatOllamaFunction/ChatOllamaFunction.ts b/packages/components/nodes/chatmodels/ChatOllamaFunction/ChatOllamaFunction.ts new file mode 100644 index 00000000000..0f16fcd41da --- /dev/null +++ b/packages/components/nodes/chatmodels/ChatOllamaFunction/ChatOllamaFunction.ts @@ -0,0 +1,809 @@ +import { HumanMessage, AIMessage, BaseMessage, AIMessageChunk, ChatMessage } from '@langchain/core/messages' +import { ChatResult } from '@langchain/core/outputs' +import { SimpleChatModel, BaseChatModel, BaseChatModelParams } from '@langchain/core/language_models/chat_models' +import { SystemMessagePromptTemplate } from '@langchain/core/prompts' +import { BaseCache } from '@langchain/core/caches' +import { type StructuredToolInterface } from '@langchain/core/tools' +import type { BaseFunctionCallOptions, BaseLanguageModelInput } from '@langchain/core/language_models/base' +import { convertToOpenAIFunction } from '@langchain/core/utils/function_calling' +import { RunnableInterface } from '@langchain/core/runnables' +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import type { BaseLanguageModelCallOptions } from '@langchain/core/language_models/base' +import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager' +import { ChatGenerationChunk } from '@langchain/core/outputs' +import type { StringWithAutocomplete } from '@langchain/core/utils/types' +import { createOllamaChatStream, createOllamaGenerateStream, type OllamaInput, type OllamaMessage } from './utils' + +const DEFAULT_TOOL_SYSTEM_TEMPLATE = `You have access to the following tools: +{tools} +You must always select one of the above tools and respond with only a JSON object matching the following schema: +{{ + "tool": , + "tool_input": +}}` + +class ChatOllamaFunction_ChatModels implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + credential: INodeParams + badge?: string + inputs: INodeParams[] + + constructor() { + this.label = 'ChatOllama Function' + this.name = 'chatOllamaFunction' + this.version = 1.0 + this.type = 'ChatOllamaFunction' + this.icon = 'Ollama.svg' + this.category = 'Chat Models' + this.description = 'Run open-source function-calling compatible LLM on Ollama' + this.baseClasses = [this.type, ...getBaseClasses(OllamaFunctions)] + this.badge = 'NEW' + this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'BaseCache', + optional: true + }, + { + label: 'Base URL', + name: 'baseUrl', + type: 'string', + default: 'http://localhost:11434' + }, + { + label: 'Model Name', + name: 'modelName', + type: 'string', + description: 'Only compatible with function calling model like mistral', + placeholder: 'mistral' + }, + { + label: 'Temperature', + name: 'temperature', + type: 'number', + description: + 'The temperature of the model. Increasing the temperature will make the model answer more creatively. (Default: 0.8). Refer to docs for more details', + step: 0.1, + default: 0.9, + optional: true + }, + { + label: 'Tool System Prompt', + name: 'toolSystemPromptTemplate', + type: 'string', + rows: 4, + description: `Under the hood, Ollama's JSON mode is being used to constrain output to JSON. Output JSON will contains two keys: tool and tool_input fields. We then parse it to execute the tool. Because different models have different strengths, it may be helpful to pass in your own system prompt.`, + warning: `Prompt must always contains {tools} and instructions to respond with a JSON object with tool and tool_input fields`, + default: DEFAULT_TOOL_SYSTEM_TEMPLATE, + placeholder: DEFAULT_TOOL_SYSTEM_TEMPLATE, + additionalParams: true, + optional: true + }, + { + label: 'Top P', + name: 'topP', + type: 'number', + description: + 'Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Top K', + name: 'topK', + type: 'number', + description: + 'Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat', + name: 'mirostat', + type: 'number', + description: + 'Enable Mirostat sampling for controlling perplexity. (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat ETA', + name: 'mirostatEta', + type: 'number', + description: + 'Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive. (Default: 0.1) Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat TAU', + name: 'mirostatTau', + type: 'number', + description: + 'Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text. (Default: 5.0) Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Context Window Size', + name: 'numCtx', + type: 'number', + description: + 'Sets the size of the context window used to generate the next token. (Default: 2048) Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of GQA groups', + name: 'numGqa', + type: 'number', + description: + 'The number of GQA groups in the transformer layer. Required for some models, for example it is 8 for llama2:70b. Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of GPU', + name: 'numGpu', + type: 'number', + description: + 'The number of layers to send to the GPU(s). On macOS it defaults to 1 to enable metal support, 0 to disable. Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of Thread', + name: 'numThread', + type: 'number', + description: + 'Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Repeat Last N', + name: 'repeatLastN', + type: 'number', + description: + 'Sets how far back for the model to look back to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Repeat Penalty', + name: 'repeatPenalty', + type: 'number', + description: + 'Sets how strongly to penalize repetitions. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Stop Sequence', + name: 'stop', + type: 'string', + rows: 4, + placeholder: 'AI assistant:', + description: + 'Sets the stop sequences to use. Use comma to seperate different sequences. Refer to docs for more details', + optional: true, + additionalParams: true + }, + { + label: 'Tail Free Sampling', + name: 'tfsZ', + type: 'number', + description: + 'Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (Default: 1). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const temperature = nodeData.inputs?.temperature as string + const baseUrl = nodeData.inputs?.baseUrl as string + const modelName = nodeData.inputs?.modelName as string + const topP = nodeData.inputs?.topP as string + const topK = nodeData.inputs?.topK as string + const mirostat = nodeData.inputs?.mirostat as string + const mirostatEta = nodeData.inputs?.mirostatEta as string + const mirostatTau = nodeData.inputs?.mirostatTau as string + const numCtx = nodeData.inputs?.numCtx as string + const numGqa = nodeData.inputs?.numGqa as string + const numGpu = nodeData.inputs?.numGpu as string + const numThread = nodeData.inputs?.numThread as string + const repeatLastN = nodeData.inputs?.repeatLastN as string + const repeatPenalty = nodeData.inputs?.repeatPenalty as string + const stop = nodeData.inputs?.stop as string + const tfsZ = nodeData.inputs?.tfsZ as string + const toolSystemPromptTemplate = nodeData.inputs?.toolSystemPromptTemplate as string + + const cache = nodeData.inputs?.cache as BaseCache + + const obj: OllamaFunctionsInput = { + baseUrl, + temperature: parseFloat(temperature), + model: modelName, + toolSystemPromptTemplate: toolSystemPromptTemplate ? toolSystemPromptTemplate : DEFAULT_TOOL_SYSTEM_TEMPLATE + } + + if (topP) obj.topP = parseFloat(topP) + if (topK) obj.topK = parseFloat(topK) + if (mirostat) obj.mirostat = parseFloat(mirostat) + if (mirostatEta) obj.mirostatEta = parseFloat(mirostatEta) + if (mirostatTau) obj.mirostatTau = parseFloat(mirostatTau) + if (numCtx) obj.numCtx = parseFloat(numCtx) + if (numGqa) obj.numGqa = parseFloat(numGqa) + if (numGpu) obj.numGpu = parseFloat(numGpu) + if (numThread) obj.numThread = parseFloat(numThread) + if (repeatLastN) obj.repeatLastN = parseFloat(repeatLastN) + if (repeatPenalty) obj.repeatPenalty = parseFloat(repeatPenalty) + if (tfsZ) obj.tfsZ = parseFloat(tfsZ) + if (stop) { + const stopSequences = stop.split(',') + obj.stop = stopSequences + } + if (cache) obj.cache = cache + + const model = new OllamaFunctions(obj) + return model + } +} + +interface ChatOllamaFunctionsCallOptions extends BaseFunctionCallOptions {} + +type OllamaFunctionsInput = Partial & + BaseChatModelParams & { + llm?: OllamaChat + toolSystemPromptTemplate?: string + } + +class OllamaFunctions extends BaseChatModel { + llm: OllamaChat + + fields?: OllamaFunctionsInput + + toolSystemPromptTemplate: string = DEFAULT_TOOL_SYSTEM_TEMPLATE + + protected defaultResponseFunction = { + name: '__conversational_response', + description: 'Respond conversationally if no other tools should be called for a given query.', + parameters: { + type: 'object', + properties: { + response: { + type: 'string', + description: 'Conversational response to the user.' + } + }, + required: ['response'] + } + } + + static lc_name(): string { + return 'OllamaFunctions' + } + + constructor(fields?: OllamaFunctionsInput) { + super(fields ?? {}) + this.fields = fields + this.llm = fields?.llm ?? new OllamaChat({ ...fields, format: 'json' }) + this.toolSystemPromptTemplate = fields?.toolSystemPromptTemplate ?? this.toolSystemPromptTemplate + } + + invocationParams() { + return this.llm.invocationParams() + } + + /** @ignore */ + _identifyingParams() { + return this.llm._identifyingParams() + } + + async _generate( + messages: BaseMessage[], + options: this['ParsedCallOptions'], + runManager?: CallbackManagerForLLMRun | undefined + ): Promise { + let functions = options.functions ?? [] + if (options.function_call !== undefined) { + functions = functions.filter((fn) => fn.name === options.function_call?.name) + if (!functions.length) { + throw new Error(`If "function_call" is specified, you must also pass a matching function in "functions".`) + } + } else if (functions.length === 0) { + functions.push(this.defaultResponseFunction) + } + const systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(this.toolSystemPromptTemplate) + const systemMessage = await systemPromptTemplate.format({ + tools: JSON.stringify(functions, null, 2) + }) + + let generatedMessages = [systemMessage, ...messages] + let isToolResponse = false + if ( + messages.length > 3 && + messages[messages.length - 1]._getType() === 'tool' && + functions.length && + messages[messages.length - 1].additional_kwargs?.name === functions[0].name + ) { + const lastToolQuestion = messages[messages.length - 3].content + const lastToolResp = messages.pop()?.content + // Pop the message again to get rid of tool call message + messages.pop()?.content + const humanMessage = new HumanMessage({ + content: `Given user question: ${lastToolQuestion} and answer: ${lastToolResp}\n\nWrite a natural language response` + }) + generatedMessages = [...messages, humanMessage] + isToolResponse = true + this.llm = new OllamaChat({ ...this.fields }) + } + const chatResult = await this.llm._generate(generatedMessages, options, runManager) + const chatGenerationContent = chatResult.generations[0].message.content + + if (typeof chatGenerationContent !== 'string') { + throw new Error('OllamaFunctions does not support non-string output.') + } + + if (isToolResponse) { + return { + generations: [ + { + message: new AIMessage({ + content: chatGenerationContent + }), + text: chatGenerationContent + } + ] + } + } + + let parsedChatResult + try { + parsedChatResult = JSON.parse(chatGenerationContent) + } catch (e) { + throw new Error(`"${this.llm.model}" did not respond with valid JSON. Please try again.`) + } + + const calledToolName = parsedChatResult.tool + const calledToolArguments = parsedChatResult.tool_input + const calledTool = functions.find((fn) => fn.name === calledToolName) + if (calledTool === undefined) { + throw new Error(`Failed to parse a function call from ${this.llm.model} output: ${chatGenerationContent}`) + } + + if (calledTool.name === this.defaultResponseFunction.name) { + return { + generations: [ + { + message: new AIMessage({ + content: calledToolArguments.response + }), + text: calledToolArguments.response + } + ] + } + } + + const responseMessageWithFunctions = new AIMessage({ + content: '', + tool_calls: [ + { + name: calledToolName, + args: calledToolArguments || {} + } + ], + invalid_tool_calls: [], + additional_kwargs: { + function_call: { + name: calledToolName, + arguments: calledToolArguments ? JSON.stringify(calledToolArguments) : '' + }, + tool_calls: [ + { + id: Date.now().toString(), + type: 'function', + function: { + name: calledToolName, + arguments: calledToolArguments ? JSON.stringify(calledToolArguments) : '' + } + } + ] + } + }) + + return { + generations: [{ message: responseMessageWithFunctions, text: '' }] + } + } + + override bindTools( + tools: StructuredToolInterface[], + kwargs?: Partial + ): RunnableInterface { + return this.bind({ + functions: tools.map((tool) => convertToOpenAIFunction(tool)), + ...kwargs + } as Partial) + } + + _llmType(): string { + return 'ollama_functions' + } + + /** @ignore */ + _combineLLMOutput() { + return [] + } +} + +export interface ChatOllamaInput extends OllamaInput {} + +interface ChatOllamaCallOptions extends BaseLanguageModelCallOptions {} + +class OllamaChat extends SimpleChatModel implements ChatOllamaInput { + static lc_name() { + return 'ChatOllama' + } + + lc_serializable = true + + model = 'llama2' + + baseUrl = 'http://localhost:11434' + + keepAlive = '5m' + + embeddingOnly?: boolean + + f16KV?: boolean + + frequencyPenalty?: number + + headers?: Record + + logitsAll?: boolean + + lowVram?: boolean + + mainGpu?: number + + mirostat?: number + + mirostatEta?: number + + mirostatTau?: number + + numBatch?: number + + numCtx?: number + + numGpu?: number + + numGqa?: number + + numKeep?: number + + numPredict?: number + + numThread?: number + + penalizeNewline?: boolean + + presencePenalty?: number + + repeatLastN?: number + + repeatPenalty?: number + + ropeFrequencyBase?: number + + ropeFrequencyScale?: number + + temperature?: number + + stop?: string[] + + tfsZ?: number + + topK?: number + + topP?: number + + typicalP?: number + + useMLock?: boolean + + useMMap?: boolean + + vocabOnly?: boolean + + format?: StringWithAutocomplete<'json'> + + constructor(fields: OllamaInput & BaseChatModelParams) { + super(fields) + this.model = fields.model ?? this.model + this.baseUrl = fields.baseUrl?.endsWith('/') ? fields.baseUrl.slice(0, -1) : fields.baseUrl ?? this.baseUrl + this.keepAlive = fields.keepAlive ?? this.keepAlive + this.embeddingOnly = fields.embeddingOnly + this.f16KV = fields.f16KV + this.frequencyPenalty = fields.frequencyPenalty + this.headers = fields.headers + this.logitsAll = fields.logitsAll + this.lowVram = fields.lowVram + this.mainGpu = fields.mainGpu + this.mirostat = fields.mirostat + this.mirostatEta = fields.mirostatEta + this.mirostatTau = fields.mirostatTau + this.numBatch = fields.numBatch + this.numCtx = fields.numCtx + this.numGpu = fields.numGpu + this.numGqa = fields.numGqa + this.numKeep = fields.numKeep + this.numPredict = fields.numPredict + this.numThread = fields.numThread + this.penalizeNewline = fields.penalizeNewline + this.presencePenalty = fields.presencePenalty + this.repeatLastN = fields.repeatLastN + this.repeatPenalty = fields.repeatPenalty + this.ropeFrequencyBase = fields.ropeFrequencyBase + this.ropeFrequencyScale = fields.ropeFrequencyScale + this.temperature = fields.temperature + this.stop = fields.stop + this.tfsZ = fields.tfsZ + this.topK = fields.topK + this.topP = fields.topP + this.typicalP = fields.typicalP + this.useMLock = fields.useMLock + this.useMMap = fields.useMMap + this.vocabOnly = fields.vocabOnly + this.format = fields.format + } + + _llmType() { + return 'ollama' + } + + /** + * A method that returns the parameters for an Ollama API call. It + * includes model and options parameters. + * @param options Optional parsed call options. + * @returns An object containing the parameters for an Ollama API call. + */ + invocationParams(options?: this['ParsedCallOptions']) { + return { + model: this.model, + format: this.format, + keep_alive: this.keepAlive, + options: { + embedding_only: this.embeddingOnly, + f16_kv: this.f16KV, + frequency_penalty: this.frequencyPenalty, + logits_all: this.logitsAll, + low_vram: this.lowVram, + main_gpu: this.mainGpu, + mirostat: this.mirostat, + mirostat_eta: this.mirostatEta, + mirostat_tau: this.mirostatTau, + num_batch: this.numBatch, + num_ctx: this.numCtx, + num_gpu: this.numGpu, + num_gqa: this.numGqa, + num_keep: this.numKeep, + num_predict: this.numPredict, + num_thread: this.numThread, + penalize_newline: this.penalizeNewline, + presence_penalty: this.presencePenalty, + repeat_last_n: this.repeatLastN, + repeat_penalty: this.repeatPenalty, + rope_frequency_base: this.ropeFrequencyBase, + rope_frequency_scale: this.ropeFrequencyScale, + temperature: this.temperature, + stop: options?.stop ?? this.stop, + tfs_z: this.tfsZ, + top_k: this.topK, + top_p: this.topP, + typical_p: this.typicalP, + use_mlock: this.useMLock, + use_mmap: this.useMMap, + vocab_only: this.vocabOnly + } + } + } + + _combineLLMOutput() { + return {} + } + + /** @deprecated */ + async *_streamResponseChunksLegacy( + input: BaseMessage[], + options: this['ParsedCallOptions'], + runManager?: CallbackManagerForLLMRun + ): AsyncGenerator { + const stream = createOllamaGenerateStream( + this.baseUrl, + { + ...this.invocationParams(options), + prompt: this._formatMessagesAsPrompt(input) + }, + { + ...options, + headers: this.headers + } + ) + for await (const chunk of stream) { + if (!chunk.done) { + yield new ChatGenerationChunk({ + text: chunk.response, + message: new AIMessageChunk({ content: chunk.response }) + }) + await runManager?.handleLLMNewToken(chunk.response ?? '') + } else { + yield new ChatGenerationChunk({ + text: '', + message: new AIMessageChunk({ content: '' }), + generationInfo: { + model: chunk.model, + total_duration: chunk.total_duration, + load_duration: chunk.load_duration, + prompt_eval_count: chunk.prompt_eval_count, + prompt_eval_duration: chunk.prompt_eval_duration, + eval_count: chunk.eval_count, + eval_duration: chunk.eval_duration + } + }) + } + } + } + + async *_streamResponseChunks( + input: BaseMessage[], + options: this['ParsedCallOptions'], + runManager?: CallbackManagerForLLMRun + ): AsyncGenerator { + try { + const stream = await this.caller.call(async () => + createOllamaChatStream( + this.baseUrl, + { + ...this.invocationParams(options), + messages: this._convertMessagesToOllamaMessages(input) + }, + { + ...options, + headers: this.headers + } + ) + ) + for await (const chunk of stream) { + if (!chunk.done) { + yield new ChatGenerationChunk({ + text: chunk.message.content, + message: new AIMessageChunk({ content: chunk.message.content }) + }) + await runManager?.handleLLMNewToken(chunk.message.content ?? '') + } else { + yield new ChatGenerationChunk({ + text: '', + message: new AIMessageChunk({ content: '' }), + generationInfo: { + model: chunk.model, + total_duration: chunk.total_duration, + load_duration: chunk.load_duration, + prompt_eval_count: chunk.prompt_eval_count, + prompt_eval_duration: chunk.prompt_eval_duration, + eval_count: chunk.eval_count, + eval_duration: chunk.eval_duration + } + }) + } + } + } catch (e: any) { + if (e.response?.status === 404) { + console.warn( + '[WARNING]: It seems you are using a legacy version of Ollama. Please upgrade to a newer version for better chat support.' + ) + yield* this._streamResponseChunksLegacy(input, options, runManager) + } else { + throw e + } + } + } + + protected _convertMessagesToOllamaMessages(messages: BaseMessage[]): OllamaMessage[] { + return messages.map((message) => { + let role + if (message._getType() === 'human') { + role = 'user' + } else if (message._getType() === 'ai' || message._getType() === 'tool') { + role = 'assistant' + } else if (message._getType() === 'system') { + role = 'system' + } else { + throw new Error(`Unsupported message type for Ollama: ${message._getType()}`) + } + let content = '' + const images = [] + if (typeof message.content === 'string') { + content = message.content + } else { + for (const contentPart of message.content) { + if (contentPart.type === 'text') { + content = `${content}\n${contentPart.text}` + } else if (contentPart.type === 'image_url' && typeof contentPart.image_url === 'string') { + const imageUrlComponents = contentPart.image_url.split(',') + // Support both data:image/jpeg;base64, format as well + images.push(imageUrlComponents[1] ?? imageUrlComponents[0]) + } else { + throw new Error( + `Unsupported message content type. Must either have type "text" or type "image_url" with a string "image_url" field.` + ) + } + } + } + return { + role, + content, + images + } + }) + } + + /** @deprecated */ + protected _formatMessagesAsPrompt(messages: BaseMessage[]): string { + const formattedMessages = messages + .map((message) => { + let messageText + if (message._getType() === 'human') { + messageText = `[INST] ${message.content} [/INST]` + } else if (message._getType() === 'ai') { + messageText = message.content + } else if (message._getType() === 'system') { + messageText = `<> ${message.content} <>` + } else if (ChatMessage.isInstance(message)) { + messageText = `\n\n${message.role[0].toUpperCase()}${message.role.slice(1)}: ${message.content}` + } else { + console.warn(`Unsupported message type passed to Ollama: "${message._getType()}"`) + messageText = '' + } + return messageText + }) + .join('\n') + return formattedMessages + } + + /** @ignore */ + async _call(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): Promise { + const chunks = [] + for await (const chunk of this._streamResponseChunks(messages, options, runManager)) { + chunks.push(chunk.message.content) + } + return chunks.join('') + } +} + +module.exports = { nodeClass: ChatOllamaFunction_ChatModels } diff --git a/packages/components/nodes/chatmodels/ChatOllamaFunction/Ollama.svg b/packages/components/nodes/chatmodels/ChatOllamaFunction/Ollama.svg new file mode 100644 index 00000000000..2dc8df5311e --- /dev/null +++ b/packages/components/nodes/chatmodels/ChatOllamaFunction/Ollama.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/chatmodels/ChatOllamaFunction/utils.ts b/packages/components/nodes/chatmodels/ChatOllamaFunction/utils.ts new file mode 100644 index 00000000000..4947b9d97a2 --- /dev/null +++ b/packages/components/nodes/chatmodels/ChatOllamaFunction/utils.ts @@ -0,0 +1,185 @@ +import { IterableReadableStream } from '@langchain/core/utils/stream' +import type { StringWithAutocomplete } from '@langchain/core/utils/types' +import { BaseLanguageModelCallOptions } from '@langchain/core/language_models/base' + +export interface OllamaInput { + embeddingOnly?: boolean + f16KV?: boolean + frequencyPenalty?: number + headers?: Record + keepAlive?: string + logitsAll?: boolean + lowVram?: boolean + mainGpu?: number + model?: string + baseUrl?: string + mirostat?: number + mirostatEta?: number + mirostatTau?: number + numBatch?: number + numCtx?: number + numGpu?: number + numGqa?: number + numKeep?: number + numPredict?: number + numThread?: number + penalizeNewline?: boolean + presencePenalty?: number + repeatLastN?: number + repeatPenalty?: number + ropeFrequencyBase?: number + ropeFrequencyScale?: number + temperature?: number + stop?: string[] + tfsZ?: number + topK?: number + topP?: number + typicalP?: number + useMLock?: boolean + useMMap?: boolean + vocabOnly?: boolean + format?: StringWithAutocomplete<'json'> +} + +export interface OllamaRequestParams { + model: string + format?: StringWithAutocomplete<'json'> + images?: string[] + options: { + embedding_only?: boolean + f16_kv?: boolean + frequency_penalty?: number + logits_all?: boolean + low_vram?: boolean + main_gpu?: number + mirostat?: number + mirostat_eta?: number + mirostat_tau?: number + num_batch?: number + num_ctx?: number + num_gpu?: number + num_gqa?: number + num_keep?: number + num_thread?: number + num_predict?: number + penalize_newline?: boolean + presence_penalty?: number + repeat_last_n?: number + repeat_penalty?: number + rope_frequency_base?: number + rope_frequency_scale?: number + temperature?: number + stop?: string[] + tfs_z?: number + top_k?: number + top_p?: number + typical_p?: number + use_mlock?: boolean + use_mmap?: boolean + vocab_only?: boolean + } +} + +export type OllamaMessage = { + role: StringWithAutocomplete<'user' | 'assistant' | 'system'> + content: string + images?: string[] +} + +export interface OllamaGenerateRequestParams extends OllamaRequestParams { + prompt: string +} + +export interface OllamaChatRequestParams extends OllamaRequestParams { + messages: OllamaMessage[] +} + +export type BaseOllamaGenerationChunk = { + model: string + created_at: string + done: boolean + total_duration?: number + load_duration?: number + prompt_eval_count?: number + prompt_eval_duration?: number + eval_count?: number + eval_duration?: number +} + +export type OllamaGenerationChunk = BaseOllamaGenerationChunk & { + response: string +} + +export type OllamaChatGenerationChunk = BaseOllamaGenerationChunk & { + message: OllamaMessage +} + +export type OllamaCallOptions = BaseLanguageModelCallOptions & { + headers?: Record +} + +async function* createOllamaStream(url: string, params: OllamaRequestParams, options: OllamaCallOptions) { + let formattedUrl = url + if (formattedUrl.startsWith('http://localhost:')) { + // Node 18 has issues with resolving "localhost" + // See https://github.com/node-fetch/node-fetch/issues/1624 + formattedUrl = formattedUrl.replace('http://localhost:', 'http://127.0.0.1:') + } + const response = await fetch(formattedUrl, { + method: 'POST', + body: JSON.stringify(params), + headers: { + 'Content-Type': 'application/json', + ...options.headers + }, + signal: options.signal + }) + if (!response.ok) { + let error + const responseText = await response.text() + try { + const json = JSON.parse(responseText) + error = new Error(`Ollama call failed with status code ${response.status}: ${json.error}`) + } catch (e) { + error = new Error(`Ollama call failed with status code ${response.status}: ${responseText}`) + } + ;(error as any).response = response + throw error + } + if (!response.body) { + throw new Error('Could not begin Ollama stream. Please check the given URL and try again.') + } + + const stream = IterableReadableStream.fromReadableStream(response.body) + + const decoder = new TextDecoder() + let extra = '' + for await (const chunk of stream) { + const decoded = extra + decoder.decode(chunk) + const lines = decoded.split('\n') + extra = lines.pop() || '' + for (const line of lines) { + try { + yield JSON.parse(line) + } catch (e) { + console.warn(`Received a non-JSON parseable chunk: ${line}`) + } + } + } +} + +export async function* createOllamaGenerateStream( + baseUrl: string, + params: OllamaGenerateRequestParams, + options: OllamaCallOptions +): AsyncGenerator { + yield* createOllamaStream(`${baseUrl}/api/generate`, params, options) +} + +export async function* createOllamaChatStream( + baseUrl: string, + params: OllamaChatRequestParams, + options: OllamaCallOptions +): AsyncGenerator { + yield* createOllamaStream(`${baseUrl}/api/chat`, params, options) +} diff --git a/packages/components/nodes/documentloaders/API/APILoader.ts b/packages/components/nodes/documentloaders/API/APILoader.ts index dda9cf4409e..0035e5956e3 100644 --- a/packages/components/nodes/documentloaders/API/APILoader.ts +++ b/packages/components/nodes/documentloaders/API/APILoader.ts @@ -82,7 +82,7 @@ class API_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -132,23 +132,31 @@ class API_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 9c475bf6dce..df98639bf9f 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -107,7 +107,7 @@ class Airtable_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -162,23 +162,31 @@ class Airtable_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/ApifyWebsiteContentCrawler/ApifyWebsiteContentCrawler.ts b/packages/components/nodes/documentloaders/ApifyWebsiteContentCrawler/ApifyWebsiteContentCrawler.ts index 207a74f6ea7..63bcea57073 100644 --- a/packages/components/nodes/documentloaders/ApifyWebsiteContentCrawler/ApifyWebsiteContentCrawler.ts +++ b/packages/components/nodes/documentloaders/ApifyWebsiteContentCrawler/ApifyWebsiteContentCrawler.ts @@ -106,7 +106,7 @@ class ApifyWebsiteContentCrawler_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -174,23 +174,31 @@ class ApifyWebsiteContentCrawler_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts b/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts index 272e226f16f..966845b6e76 100644 --- a/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts +++ b/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts @@ -93,7 +93,7 @@ class Cheerio_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -178,23 +178,31 @@ class Cheerio_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Confluence/Confluence.ts b/packages/components/nodes/documentloaders/Confluence/Confluence.ts index b2496f67529..c77340b8d33 100644 --- a/packages/components/nodes/documentloaders/Confluence/Confluence.ts +++ b/packages/components/nodes/documentloaders/Confluence/Confluence.ts @@ -73,7 +73,7 @@ class Confluence_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -128,23 +128,31 @@ class Confluence_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Csv/Csv.ts b/packages/components/nodes/documentloaders/Csv/Csv.ts index ec0fe683a1a..2f74e1c6acd 100644 --- a/packages/components/nodes/documentloaders/Csv/Csv.ts +++ b/packages/components/nodes/documentloaders/Csv/Csv.ts @@ -1,8 +1,8 @@ import { omit } from 'lodash' -import { ICommonObject, IDocument, INode, INodeData, INodeParams } from '../../../src/Interface' +import { ICommonObject, IDocument, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { TextSplitter } from 'langchain/text_splitter' import { CSVLoader } from 'langchain/document_loaders/fs/csv' -import { getFileFromStorage } from '../../../src' +import { getFileFromStorage, handleEscapeCharacters } from '../../../src' class Csv_DocumentLoaders implements INode { label: string @@ -14,11 +14,12 @@ class Csv_DocumentLoaders implements INode { category: string baseClasses: string[] inputs: INodeParams[] + outputs: INodeOutputsValue[] constructor() { this.label = 'Csv File' this.name = 'csvFile' - this.version = 1.0 + this.version = 2.0 this.type = 'Document' this.icon = 'csv.svg' this.category = 'Document Loaders' @@ -59,12 +60,26 @@ class Csv_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true } ] + this.outputs = [ + { + label: 'Document', + name: 'document', + description: 'Array of document objects containing metadata and pageContent', + baseClasses: [...this.baseClasses, 'json'] + }, + { + label: 'Text', + name: 'text', + description: 'Concatenated string from pageContent of documents', + baseClasses: ['string', 'json'] + } + ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { @@ -72,6 +87,7 @@ class Csv_DocumentLoaders implements INode { const csvFileBase64 = nodeData.inputs?.csvFile as string const columnName = nodeData.inputs?.columnName as string const metadata = nodeData.inputs?.metadata + const output = nodeData.outputs?.output as string const _omitMetadataKeys = nodeData.inputs?.omitMetadataKeys as string let omitMetadataKeys: string[] = [] @@ -128,27 +144,43 @@ class Csv_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } - return docs + if (output === 'document') { + return docs + } else { + let finaltext = '' + for (const doc of docs) { + finaltext += `${doc.pageContent}\n` + } + return handleEscapeCharacters(finaltext, false) + } } } diff --git a/packages/components/nodes/documentloaders/DocumentStore/DocStoreLoader.ts b/packages/components/nodes/documentloaders/DocumentStore/DocStoreLoader.ts index c7075265192..7253f9c939a 100644 --- a/packages/components/nodes/documentloaders/DocumentStore/DocStoreLoader.ts +++ b/packages/components/nodes/documentloaders/DocumentStore/DocStoreLoader.ts @@ -1,6 +1,7 @@ import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { DataSource } from 'typeorm' import { Document } from '@langchain/core/documents' +import { handleEscapeCharacters } from '../../../src' class DocStore_DocumentLoaders implements INode { label: string @@ -83,12 +84,22 @@ class DocStore_DocumentLoaders implements INode { const chunks = await appDataSource .getRepository(databaseEntities['DocumentStoreFileChunk']) .find({ where: { storeId: selectedStore } }) + const output = nodeData.outputs?.output as string const finalDocs = [] for (const chunk of chunks) { finalDocs.push(new Document({ pageContent: chunk.pageContent, metadata: JSON.parse(chunk.metadata) })) } - return finalDocs + + 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/Docx/Docx.ts b/packages/components/nodes/documentloaders/Docx/Docx.ts index 3ee6ef34e0d..e473ae617d4 100644 --- a/packages/components/nodes/documentloaders/Docx/Docx.ts +++ b/packages/components/nodes/documentloaders/Docx/Docx.ts @@ -51,7 +51,7 @@ class Docx_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -119,23 +119,31 @@ class Docx_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Figma/Figma.ts b/packages/components/nodes/documentloaders/Figma/Figma.ts index e7f88b52d16..023168aa7af 100644 --- a/packages/components/nodes/documentloaders/Figma/Figma.ts +++ b/packages/components/nodes/documentloaders/Figma/Figma.ts @@ -74,7 +74,7 @@ class Figma_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -111,23 +111,31 @@ class Figma_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Folder/Folder.ts b/packages/components/nodes/documentloaders/Folder/Folder.ts index e3392a77b7e..15cb10a4062 100644 --- a/packages/components/nodes/documentloaders/Folder/Folder.ts +++ b/packages/components/nodes/documentloaders/Folder/Folder.ts @@ -79,7 +79,7 @@ class Folder_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -162,23 +162,31 @@ class Folder_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Gitbook/Gitbook.ts b/packages/components/nodes/documentloaders/Gitbook/Gitbook.ts index 6faba9ef37e..e5c524a4ec7 100644 --- a/packages/components/nodes/documentloaders/Gitbook/Gitbook.ts +++ b/packages/components/nodes/documentloaders/Gitbook/Gitbook.ts @@ -58,7 +58,7 @@ class Gitbook_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -85,23 +85,31 @@ class Gitbook_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Github/Github.ts b/packages/components/nodes/documentloaders/Github/Github.ts index 5b585f2c7d5..0df11444dd8 100644 --- a/packages/components/nodes/documentloaders/Github/Github.ts +++ b/packages/components/nodes/documentloaders/Github/Github.ts @@ -100,7 +100,7 @@ class Github_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -145,23 +145,31 @@ class Github_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Json/Json.ts b/packages/components/nodes/documentloaders/Json/Json.ts index 64ef84dd3a6..7b12fb3a7d8 100644 --- a/packages/components/nodes/documentloaders/Json/Json.ts +++ b/packages/components/nodes/documentloaders/Json/Json.ts @@ -59,7 +59,7 @@ class Json_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -135,23 +135,31 @@ class Json_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Jsonlines/Jsonlines.ts b/packages/components/nodes/documentloaders/Jsonlines/Jsonlines.ts index 82b11d132cf..48654c4c0e6 100644 --- a/packages/components/nodes/documentloaders/Jsonlines/Jsonlines.ts +++ b/packages/components/nodes/documentloaders/Jsonlines/Jsonlines.ts @@ -58,7 +58,7 @@ class Jsonlines_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -129,23 +129,31 @@ class Jsonlines_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Notion/NotionDB.ts b/packages/components/nodes/documentloaders/Notion/NotionDB.ts index dd21cc8e3cf..38e48ba48f9 100644 --- a/packages/components/nodes/documentloaders/Notion/NotionDB.ts +++ b/packages/components/nodes/documentloaders/Notion/NotionDB.ts @@ -58,7 +58,7 @@ class NotionDB_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -104,23 +104,31 @@ class NotionDB_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Notion/NotionFolder.ts b/packages/components/nodes/documentloaders/Notion/NotionFolder.ts index 22184b493cb..4e473891a42 100644 --- a/packages/components/nodes/documentloaders/Notion/NotionFolder.ts +++ b/packages/components/nodes/documentloaders/Notion/NotionFolder.ts @@ -51,7 +51,7 @@ class NotionFolder_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -83,23 +83,31 @@ class NotionFolder_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Notion/NotionPage.ts b/packages/components/nodes/documentloaders/Notion/NotionPage.ts index 3e88a6e3541..29e873524d4 100644 --- a/packages/components/nodes/documentloaders/Notion/NotionPage.ts +++ b/packages/components/nodes/documentloaders/Notion/NotionPage.ts @@ -59,7 +59,7 @@ class NotionPage_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -101,23 +101,31 @@ class NotionPage_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Pdf/Pdf.ts b/packages/components/nodes/documentloaders/Pdf/Pdf.ts index 9199c9bef6f..13cdf87c8cd 100644 --- a/packages/components/nodes/documentloaders/Pdf/Pdf.ts +++ b/packages/components/nodes/documentloaders/Pdf/Pdf.ts @@ -74,7 +74,7 @@ class Pdf_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -132,23 +132,31 @@ class Pdf_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/PlainText/PlainText.ts b/packages/components/nodes/documentloaders/PlainText/PlainText.ts index 2d3d89602e4..03504d7b872 100644 --- a/packages/components/nodes/documentloaders/PlainText/PlainText.ts +++ b/packages/components/nodes/documentloaders/PlainText/PlainText.ts @@ -54,7 +54,7 @@ class PlainText_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -104,23 +104,31 @@ class PlainText_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Playwright/Playwright.ts b/packages/components/nodes/documentloaders/Playwright/Playwright.ts index 4472e6bb39e..281fb5424bf 100644 --- a/packages/components/nodes/documentloaders/Playwright/Playwright.ts +++ b/packages/components/nodes/documentloaders/Playwright/Playwright.ts @@ -121,7 +121,7 @@ class Playwright_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -217,23 +217,31 @@ class Playwright_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts index baca4abe42e..b9a80472f2d 100644 --- a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts +++ b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts @@ -122,7 +122,7 @@ class Puppeteer_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -218,23 +218,31 @@ class Puppeteer_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/S3File/S3File.ts b/packages/components/nodes/documentloaders/S3File/S3File.ts index c01500e1fb9..fcb438ef03c 100644 --- a/packages/components/nodes/documentloaders/S3File/S3File.ts +++ b/packages/components/nodes/documentloaders/S3File/S3File.ts @@ -427,7 +427,7 @@ class S3_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -561,25 +561,33 @@ class S3_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata, - [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata, + [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata, + [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/SearchApi/SearchAPI.ts b/packages/components/nodes/documentloaders/SearchApi/SearchAPI.ts index 1a2db0e279a..e7130798780 100644 --- a/packages/components/nodes/documentloaders/SearchApi/SearchAPI.ts +++ b/packages/components/nodes/documentloaders/SearchApi/SearchAPI.ts @@ -68,7 +68,7 @@ class SearchAPI_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -112,23 +112,31 @@ class SearchAPI_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/SerpApi/SerpAPI.ts b/packages/components/nodes/documentloaders/SerpApi/SerpAPI.ts index db735a961e2..ad536054d58 100644 --- a/packages/components/nodes/documentloaders/SerpApi/SerpAPI.ts +++ b/packages/components/nodes/documentloaders/SerpApi/SerpAPI.ts @@ -58,7 +58,7 @@ class SerpAPI_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -86,23 +86,31 @@ class SerpAPI_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Text/Text.ts b/packages/components/nodes/documentloaders/Text/Text.ts index 6589fb75eb8..c974cae2e62 100644 --- a/packages/components/nodes/documentloaders/Text/Text.ts +++ b/packages/components/nodes/documentloaders/Text/Text.ts @@ -53,7 +53,7 @@ class Text_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -137,23 +137,31 @@ class Text_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts index d80f2e5b1f0..f1cf6c457d1 100644 --- a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts +++ b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts @@ -414,7 +414,7 @@ class UnstructuredFile_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -518,25 +518,33 @@ class UnstructuredFile_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata, - [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata, + [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata, + [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts index 83d7c85a8cc..f04bee35820 100644 --- a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts +++ b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts @@ -393,7 +393,7 @@ class UnstructuredFolder_DocumentLoaders implements INode { type: 'string', rows: 4, description: - 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma', + 'Each document loader comes with a default set of metadata keys that are extracted from the document. You can use this field to omit some of the default metadata keys. The value should be a list of keys, seperated by comma. Use * to omit all metadata keys execept the ones you specify in the Additional Metadata field', placeholder: 'key1, key2, key3.nestedKey1', optional: true, additionalParams: true @@ -456,25 +456,33 @@ class UnstructuredFolder_DocumentLoaders implements INode { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - ...parsedMetadata, - [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? { + ...parsedMetadata + } + : omit( + { + ...doc.metadata, + ...parsedMetadata, + [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey + }, + omitMetadataKeys + ) })) } else { docs = docs.map((doc) => ({ ...doc, - metadata: omit( - { - ...doc.metadata, - [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey - }, - omitMetadataKeys - ) + metadata: + _omitMetadataKeys === '*' + ? {} + : omit( + { + ...doc.metadata, + [sourceIdKey]: doc.metadata[sourceIdKey] || sourceIdKey + }, + omitMetadataKeys + ) })) } diff --git a/packages/components/nodes/engine/ChatEngine/ContextChatEngine.ts b/packages/components/nodes/engine/ChatEngine/ContextChatEngine.ts index f7e3ff4fc21..ac944d4414f 100644 --- a/packages/components/nodes/engine/ChatEngine/ContextChatEngine.ts +++ b/packages/components/nodes/engine/ChatEngine/ContextChatEngine.ts @@ -71,6 +71,7 @@ class ContextChatEngine_LlamaIndex implements INode { const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string const memory = nodeData.inputs?.memory as FlowiseMemory const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean + const prependMessages = options?.prependMessages const chatHistory = [] as ChatMessage[] @@ -83,7 +84,7 @@ class ContextChatEngine_LlamaIndex implements INode { const chatEngine = new ContextChatEngine({ chatModel: model, retriever: vectorStoreRetriever }) - const msgs = (await memory.getChatMessages(this.sessionId, false)) as IMessage[] + const msgs = (await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[] for (const message of msgs) { if (message.type === 'apiMessage') { chatHistory.push({ diff --git a/packages/components/nodes/engine/ChatEngine/SimpleChatEngine.ts b/packages/components/nodes/engine/ChatEngine/SimpleChatEngine.ts index 221c60ada98..5734288d1da 100644 --- a/packages/components/nodes/engine/ChatEngine/SimpleChatEngine.ts +++ b/packages/components/nodes/engine/ChatEngine/SimpleChatEngine.ts @@ -56,6 +56,7 @@ class SimpleChatEngine_LlamaIndex implements INode { const model = nodeData.inputs?.model as LLM const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string const memory = nodeData.inputs?.memory as FlowiseMemory + const prependMessages = options?.prependMessages const chatHistory = [] as ChatMessage[] @@ -68,7 +69,7 @@ class SimpleChatEngine_LlamaIndex implements INode { const chatEngine = new SimpleChatEngine({ llm: model }) - const msgs = (await memory.getChatMessages(this.sessionId, false)) as IMessage[] + const msgs = (await memory.getChatMessages(this.sessionId, false, prependMessages)) as IMessage[] for (const message of msgs) { if (message.type === 'apiMessage') { chatHistory.push({ diff --git a/packages/components/nodes/memory/BufferMemory/BufferMemory.ts b/packages/components/nodes/memory/BufferMemory/BufferMemory.ts index 80bf7f96385..d9557febee5 100644 --- a/packages/components/nodes/memory/BufferMemory/BufferMemory.ts +++ b/packages/components/nodes/memory/BufferMemory/BufferMemory.ts @@ -94,7 +94,11 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { this.chatflowid = fields.chatflowid } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { const id = overrideSessionId ? overrideSessionId : this.sessionId if (!id) return [] @@ -108,6 +112,10 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { } }) + if (prependMessages?.length) { + chatMessage.unshift(...prependMessages) + } + if (returnBaseMessages) { return mapChatMessageToBaseMessage(chatMessage) } diff --git a/packages/components/nodes/memory/BufferWindowMemory/BufferWindowMemory.ts b/packages/components/nodes/memory/BufferWindowMemory/BufferWindowMemory.ts index 66d5549c828..422cac55fcd 100644 --- a/packages/components/nodes/memory/BufferWindowMemory/BufferWindowMemory.ts +++ b/packages/components/nodes/memory/BufferWindowMemory/BufferWindowMemory.ts @@ -105,7 +105,11 @@ class BufferWindowMemoryExtended extends FlowiseWindowMemory implements MemoryMe this.chatflowid = fields.chatflowid } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { const id = overrideSessionId ? overrideSessionId : this.sessionId if (!id) return [] @@ -123,6 +127,10 @@ class BufferWindowMemoryExtended extends FlowiseWindowMemory implements MemoryMe // reverse the order of human and ai messages if (chatMessage.length) chatMessage.reverse() + if (prependMessages?.length) { + chatMessage.unshift(...prependMessages) + } + if (returnBaseMessages) { return mapChatMessageToBaseMessage(chatMessage) } diff --git a/packages/components/nodes/memory/ConversationSummaryBufferMemory/ConversationSummaryBufferMemory.ts b/packages/components/nodes/memory/ConversationSummaryBufferMemory/ConversationSummaryBufferMemory.ts index c57560b738e..5f58b0ca823 100644 --- a/packages/components/nodes/memory/ConversationSummaryBufferMemory/ConversationSummaryBufferMemory.ts +++ b/packages/components/nodes/memory/ConversationSummaryBufferMemory/ConversationSummaryBufferMemory.ts @@ -114,7 +114,11 @@ class ConversationSummaryBufferMemoryExtended extends FlowiseSummaryBufferMemory this.chatflowid = fields.chatflowid } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { const id = overrideSessionId ? overrideSessionId : this.sessionId if (!id) return [] @@ -128,6 +132,10 @@ class ConversationSummaryBufferMemoryExtended extends FlowiseSummaryBufferMemory } }) + if (prependMessages?.length) { + chatMessage.unshift(...prependMessages) + } + let baseMessages = mapChatMessageToBaseMessage(chatMessage) // Prune baseMessages if it exceeds max token limit diff --git a/packages/components/nodes/memory/ConversationSummaryMemory/ConversationSummaryMemory.ts b/packages/components/nodes/memory/ConversationSummaryMemory/ConversationSummaryMemory.ts index 29614da5c67..bd1c5617d90 100644 --- a/packages/components/nodes/memory/ConversationSummaryMemory/ConversationSummaryMemory.ts +++ b/packages/components/nodes/memory/ConversationSummaryMemory/ConversationSummaryMemory.ts @@ -104,7 +104,11 @@ class ConversationSummaryMemoryExtended extends FlowiseSummaryMemory implements this.chatflowid = fields.chatflowid } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { const id = overrideSessionId ? overrideSessionId : this.sessionId if (!id) return [] @@ -119,6 +123,10 @@ class ConversationSummaryMemoryExtended extends FlowiseSummaryMemory implements } }) + if (prependMessages?.length) { + chatMessage.unshift(...prependMessages) + } + const baseMessages = mapChatMessageToBaseMessage(chatMessage) // Get summary diff --git a/packages/components/nodes/memory/DynamoDb/DynamoDb.ts b/packages/components/nodes/memory/DynamoDb/DynamoDb.ts index 77835709086..2c64d42e603 100644 --- a/packages/components/nodes/memory/DynamoDb/DynamoDb.ts +++ b/packages/components/nodes/memory/DynamoDb/DynamoDb.ts @@ -12,7 +12,13 @@ import { import { DynamoDBChatMessageHistory } from '@langchain/community/stores/message/dynamodb' import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, StoredMessage, BaseMessage } from '@langchain/core/messages' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { + convertBaseMessagetoIMessage, + getBaseClasses, + getCredentialData, + getCredentialParam, + mapChatMessageToBaseMessage +} from '../../../src/utils' import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' class DynamoDb_Memory implements INode { @@ -219,7 +225,11 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { await client.send(new UpdateItemCommand(params)) } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { if (!this.dynamodbClient) return [] const dynamoKey = overrideSessionId ? this.overrideDynamoKey(overrideSessionId) : this.dynamoKey @@ -243,6 +253,9 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { })) .filter((x): x is StoredMessage => x.type !== undefined && x.data.content !== undefined) const baseMessages = messages.map(mapStoredMessageToChatMessage) + if (prependMessages?.length) { + baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages)) + } return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) } diff --git a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts index cf56e1f9c46..f4351aaf8aa 100644 --- a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts +++ b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts @@ -2,7 +2,13 @@ import { MongoClient, Collection, Document } from 'mongodb' import { MongoDBChatMessageHistory } from '@langchain/mongodb' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } from '@langchain/core/messages' -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { + convertBaseMessagetoIMessage, + getBaseClasses, + getCredentialData, + getCredentialParam, + mapChatMessageToBaseMessage +} from '../../../src/utils' import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' let mongoClientSingleton: MongoClient @@ -151,13 +157,20 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { this.collection = fields.collection } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { if (!this.collection) return [] const id = overrideSessionId ? overrideSessionId : this.sessionId const document = await this.collection.findOne({ sessionId: id }) const messages = document?.messages || [] const baseMessages = messages.map(mapStoredMessageToChatMessage) + if (prependMessages?.length) { + baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages)) + } return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) } diff --git a/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts b/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts index b9f27a9094f..9900b8cd0fe 100644 --- a/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts @@ -4,7 +4,13 @@ import { BufferMemory, BufferMemoryInput } from 'langchain/memory' import { RedisChatMessageHistory, RedisChatMessageHistoryInput } from '@langchain/community/stores/message/ioredis' import { mapStoredMessageToChatMessage, BaseMessage, AIMessage, HumanMessage } from '@langchain/core/messages' import { INode, INodeData, INodeParams, ICommonObject, MessageType, IMessage, MemoryMethods, FlowiseMemory } from '../../../src/Interface' -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { + convertBaseMessagetoIMessage, + getBaseClasses, + getCredentialData, + getCredentialParam, + mapChatMessageToBaseMessage +} from '../../../src/utils' let redisClientSingleton: Redis let redisClientOption: RedisOptions @@ -190,13 +196,20 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { this.sessionTTL = fields.sessionTTL } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { if (!this.redisClient) return [] const id = overrideSessionId ? overrideSessionId : this.sessionId const rawStoredMessages = await this.redisClient.lrange(id, this.windowSize ? this.windowSize * -1 : 0, -1) const orderedMessages = rawStoredMessages.reverse().map((message) => JSON.parse(message)) const baseMessages = orderedMessages.map(mapStoredMessageToChatMessage) + if (prependMessages?.length) { + baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages)) + } return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) } diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index a2201790cc6..7eb9b3906ce 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -4,7 +4,13 @@ import { BufferMemory, BufferMemoryInput } from 'langchain/memory' import { UpstashRedisChatMessageHistory } from '@langchain/community/stores/message/upstash_redis' import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, StoredMessage, BaseMessage } from '@langchain/core/messages' import { FlowiseMemory, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { + convertBaseMessagetoIMessage, + getBaseClasses, + getCredentialData, + getCredentialParam, + mapChatMessageToBaseMessage +} from '../../../src/utils' import { ICommonObject } from '../../../src/Interface' let redisClientSingleton: Redis @@ -143,7 +149,11 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { this.sessionTTL = fields.sessionTTL } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { if (!this.redisClient) return [] const id = overrideSessionId ? overrideSessionId : this.sessionId @@ -151,6 +161,9 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { const orderedMessages = rawStoredMessages.reverse() const previousMessages = orderedMessages.filter((x): x is StoredMessage => x.type !== undefined && x.data.content !== undefined) const baseMessages = previousMessages.map(mapStoredMessageToChatMessage) + if (prependMessages?.length) { + baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages)) + } return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) } diff --git a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts index c8d3d155230..3f654146dc6 100644 --- a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts +++ b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts @@ -2,7 +2,13 @@ import { ZepMemory, ZepMemoryInput } from '@langchain/community/memory/zep' import { BaseMessage } from '@langchain/core/messages' import { InputValues, MemoryVariables, OutputValues } from 'langchain/memory' import { IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType, ICommonObject } from '../../../src/Interface' -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { + convertBaseMessagetoIMessage, + getBaseClasses, + getCredentialData, + getCredentialParam, + mapChatMessageToBaseMessage +} from '../../../src/utils' class ZepMemory_Memory implements INode { label: string @@ -161,10 +167,17 @@ class ZepMemoryExtended extends ZepMemory implements MemoryMethods { return super.clear() } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { const id = overrideSessionId ? overrideSessionId : this.sessionId const memoryVariables = await this.loadMemoryVariables({}, id) const baseMessages = memoryVariables[this.memoryKey] + if (prependMessages?.length) { + baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages)) + } return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) } diff --git a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts index d5c950f4bb1..6be233bbfaf 100644 --- a/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts +++ b/packages/components/nodes/memory/ZepMemoryCloud/ZepMemoryCloud.ts @@ -1,5 +1,11 @@ import { IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { + convertBaseMessagetoIMessage, + getBaseClasses, + getCredentialData, + getCredentialParam, + mapChatMessageToBaseMessage +} from '../../../src/utils' import { ZepMemory, ZepMemoryInput } from '@getzep/zep-cloud/langchain' import { ICommonObject } from '../../../src' @@ -155,10 +161,17 @@ class ZepMemoryExtended extends ZepMemory implements MemoryMethods { return super.clear() } - async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { + async getChatMessages( + overrideSessionId = '', + returnBaseMessages = false, + prependMessages?: IMessage[] + ): Promise { const id = overrideSessionId ? overrideSessionId : this.sessionId const memoryVariables = await this.loadMemoryVariables({}, id) const baseMessages = memoryVariables[this.memoryKey] + if (prependMessages?.length) { + baseMessages.unshift(...mapChatMessageToBaseMessage(prependMessages)) + } return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) } diff --git a/packages/components/nodes/multiagents/Supervisor/Supervisor.ts b/packages/components/nodes/multiagents/Supervisor/Supervisor.ts new file mode 100644 index 00000000000..0a799d9a21f --- /dev/null +++ b/packages/components/nodes/multiagents/Supervisor/Supervisor.ts @@ -0,0 +1,454 @@ +import { flatten } from 'lodash' +import { BaseChatModel } from '@langchain/core/language_models/chat_models' +import { Runnable, RunnableConfig } from '@langchain/core/runnables' +import { ChatPromptTemplate, MessagesPlaceholder, HumanMessagePromptTemplate } from '@langchain/core/prompts' +import { + ICommonObject, + IMultiAgentNode, + INode, + INodeData, + INodeParams, + ITeamState, + IVisionChatModal, + MessageContentImageUrl +} from '../../../src/Interface' +import { Moderation } from '../../moderation/Moderation' +import { z } from 'zod' +import { StructuredTool } from '@langchain/core/tools' +import { AgentExecutor, JsonOutputToolsParser, ToolCallingAgentOutputParser } from '../../../src/agents' +import { ChatMistralAI } from '@langchain/mistralai' +import { ChatOpenAI } from '../../chatmodels/ChatOpenAI/FlowiseChatOpenAI' +import { ChatAnthropic } from '../../chatmodels/ChatAnthropic/FlowiseChatAnthropic' +import { ChatGoogleGenerativeAI } from '../../chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI' +import { addImagesToMessages, llmSupportsVision } from '../../../src/multiModalUtils' + +const sysPrompt = `You are a supervisor tasked with managing a conversation between the following workers: {team_members}. +Given the following user request, respond with the worker to act next. +Each worker will perform a task and respond with their results and status. +When finished, respond with FINISH. +Select strategically to minimize the number of steps taken.` + +const routerToolName = 'route' + +class Supervisor_MultiAgents implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + credential: INodeParams + inputs?: INodeParams[] + badge?: string + + constructor() { + this.label = 'Supervisor' + this.name = 'supervisor' + this.version = 1.0 + this.type = 'Supervisor' + this.icon = 'supervisor.svg' + this.category = 'Multi Agents' + this.baseClasses = [this.type] + this.inputs = [ + { + label: 'Supervisor Name', + name: 'supervisorName', + type: 'string', + placeholder: 'Supervisor', + default: 'Supervisor' + }, + { + label: 'Supervisor Prompt', + name: 'supervisorPrompt', + type: 'string', + description: 'Prompt must contains {team_members}', + rows: 4, + default: sysPrompt, + additionalParams: true + }, + { + label: 'Tool Calling Chat Model', + name: 'model', + type: 'BaseChatModel', + description: `Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, GroqChat. Best result with GPT-4 model` + }, + { + label: 'Recursion Limit', + name: 'recursionLimit', + type: 'number', + description: 'Maximum number of times a call can recurse. If not provided, defaults to 100.', + default: 100, + additionalParams: true + }, + { + label: 'Input Moderation', + description: 'Detect text that could generate harmful output and prevent it from being sent to the language model', + name: 'inputModeration', + type: 'Moderation', + optional: true, + list: true + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const llm = nodeData.inputs?.model as BaseChatModel + const supervisorPrompt = nodeData.inputs?.supervisorPrompt as string + const supervisorLabel = nodeData.inputs?.supervisorName as string + const _recursionLimit = nodeData.inputs?.recursionLimit as string + const recursionLimit = _recursionLimit ? parseFloat(_recursionLimit) : 100 + const moderations = (nodeData.inputs?.inputModeration as Moderation[]) ?? [] + + const abortControllerSignal = options.signal as AbortController + + const workersNodes: IMultiAgentNode[] = + nodeData.inputs?.workerNodes && nodeData.inputs?.workerNodes.length ? flatten(nodeData.inputs?.workerNodes) : [] + const workersNodeNames = workersNodes.map((node: IMultiAgentNode) => node.name) + + if (!supervisorLabel) throw new Error('Supervisor name is required!') + + const supervisorName = supervisorLabel.toLowerCase().replace(/\s/g, '_').trim() + + let multiModalMessageContent: MessageContentImageUrl[] = [] + + async function createTeamSupervisor(llm: BaseChatModel, systemPrompt: string, members: string[]): Promise { + const memberOptions = ['FINISH', ...members] + + systemPrompt = systemPrompt.replaceAll('{team_members}', members.join(', ')) + + let userPrompt = `Given the conversation above, who should act next? Or should we FINISH? Select one of: ${memberOptions.join( + ', ' + )}` + + const tool = new RouteTool({ + schema: z.object({ + reasoning: z.string(), + next: z.enum(['FINISH', ...members]), + instructions: z.string().describe('The specific instructions of the sub-task the next role should accomplish.') + }) + }) + + let supervisor + + if (llm instanceof ChatMistralAI) { + let prompt = ChatPromptTemplate.fromMessages([ + ['system', systemPrompt], + new MessagesPlaceholder('messages'), + ['human', userPrompt] + ]) + + const messages = await processImageMessage(1, llm, prompt, nodeData, options) + prompt = messages.prompt + multiModalMessageContent = messages.multiModalMessageContent + + // Force Mistral to use tool + const modelWithTool = llm.bind({ + tools: [tool], + tool_choice: 'any', + signal: abortControllerSignal ? abortControllerSignal.signal : undefined + }) + + const outputParser = new JsonOutputToolsParser() + + supervisor = prompt + .pipe(modelWithTool) + .pipe(outputParser) + .pipe((x) => { + if (Array.isArray(x) && x.length) { + const toolAgentAction = x[0] + return { + next: Object.keys(toolAgentAction.args).length ? toolAgentAction.args.next : 'FINISH', + instructions: Object.keys(toolAgentAction.args).length + ? toolAgentAction.args.instructions + : 'Conversation finished', + team_members: members.join(', ') + } + } else { + return { + next: 'FINISH', + instructions: 'Conversation finished', + team_members: members.join(', ') + } + } + }) + } else if (llm instanceof ChatAnthropic) { + // Force Anthropic to use tool : https://docs.anthropic.com/claude/docs/tool-use#forcing-tool-use + userPrompt = `Given the conversation above, who should act next? Or should we FINISH? Select one of: ${memberOptions.join( + ', ' + )}. Use the ${routerToolName} tool in your response.` + + let prompt = ChatPromptTemplate.fromMessages([ + ['system', systemPrompt], + new MessagesPlaceholder('messages'), + ['human', userPrompt] + ]) + + const messages = await processImageMessage(1, llm, prompt, nodeData, options) + prompt = messages.prompt + multiModalMessageContent = messages.multiModalMessageContent + + if (llm.bindTools === undefined) { + throw new Error(`This agent only compatible with function calling models.`) + } + + const modelWithTool = llm.bindTools([tool]) + + const outputParser = new ToolCallingAgentOutputParser() + + supervisor = prompt + .pipe(modelWithTool) + .pipe(outputParser) + .pipe((x) => { + if (Array.isArray(x) && x.length) { + const toolAgentAction = x[0] as any + return { + next: toolAgentAction.toolInput.next, + instructions: toolAgentAction.toolInput.instructions, + team_members: members.join(', ') + } + } else if (typeof x === 'object' && 'returnValues' in x) { + return { + next: 'FINISH', + instructions: x.returnValues?.output, + team_members: members.join(', ') + } + } else { + return { + next: 'FINISH', + instructions: 'Conversation finished', + team_members: members.join(', ') + } + } + }) + } else if (llm instanceof ChatOpenAI) { + let prompt = ChatPromptTemplate.fromMessages([ + ['system', systemPrompt], + new MessagesPlaceholder('messages'), + ['human', userPrompt] + ]) + + const messages = await processImageMessage(1, llm, prompt, nodeData, options) + prompt = messages.prompt + multiModalMessageContent = messages.multiModalMessageContent + + // Force OpenAI to use tool + const modelWithTool = llm.bind({ + tools: [tool], + tool_choice: { type: 'function', function: { name: routerToolName } }, + signal: abortControllerSignal ? abortControllerSignal.signal : undefined + }) + + const outputParser = new ToolCallingAgentOutputParser() + + supervisor = prompt + .pipe(modelWithTool) + .pipe(outputParser) + .pipe((x) => { + if (Array.isArray(x) && x.length) { + const toolAgentAction = x[0] as any + return { + next: toolAgentAction.toolInput.next, + instructions: toolAgentAction.toolInput.instructions, + team_members: members.join(', ') + } + } else if (typeof x === 'object' && 'returnValues' in x) { + return { + next: 'FINISH', + instructions: x.returnValues?.output, + team_members: members.join(', ') + } + } else { + return { + next: 'FINISH', + instructions: 'Conversation finished', + team_members: members.join(', ') + } + } + }) + } else if (llm instanceof ChatGoogleGenerativeAI) { + /* + * Gemini doesn't have system message and messages have to be alternate between model and user + * So we have to place the system + human prompt at last + */ + let prompt = ChatPromptTemplate.fromMessages([ + ['human', systemPrompt], + ['ai', ''], + new MessagesPlaceholder('messages'), + ['ai', ''], + ['human', userPrompt] + ]) + + const messages = await processImageMessage(2, llm, prompt, nodeData, options) + prompt = messages.prompt + multiModalMessageContent = messages.multiModalMessageContent + + if (llm.bindTools === undefined) { + throw new Error(`This agent only compatible with function calling models.`) + } + const modelWithTool = llm.bindTools([tool]) + + const outputParser = new ToolCallingAgentOutputParser() + + supervisor = prompt + .pipe(modelWithTool) + .pipe(outputParser) + .pipe((x) => { + if (Array.isArray(x) && x.length) { + const toolAgentAction = x[0] as any + return { + next: toolAgentAction.toolInput.next, + instructions: toolAgentAction.toolInput.instructions, + team_members: members.join(', ') + } + } else if (typeof x === 'object' && 'returnValues' in x) { + return { + next: 'FINISH', + instructions: x.returnValues?.output, + team_members: members.join(', ') + } + } else { + return { + next: 'FINISH', + instructions: 'Conversation finished', + team_members: members.join(', ') + } + } + }) + } else { + let prompt = ChatPromptTemplate.fromMessages([ + ['system', systemPrompt], + new MessagesPlaceholder('messages'), + ['human', userPrompt] + ]) + + const messages = await processImageMessage(1, llm, prompt, nodeData, options) + prompt = messages.prompt + multiModalMessageContent = messages.multiModalMessageContent + + if (llm.bindTools === undefined) { + throw new Error(`This agent only compatible with function calling models.`) + } + const modelWithTool = llm.bindTools([tool]) + + const outputParser = new ToolCallingAgentOutputParser() + + supervisor = prompt + .pipe(modelWithTool) + .pipe(outputParser) + .pipe((x) => { + if (Array.isArray(x) && x.length) { + const toolAgentAction = x[0] as any + return { + next: toolAgentAction.toolInput.next, + instructions: toolAgentAction.toolInput.instructions, + team_members: members.join(', ') + } + } else if (typeof x === 'object' && 'returnValues' in x) { + return { + next: 'FINISH', + instructions: x.returnValues?.output, + team_members: members.join(', ') + } + } else { + return { + next: 'FINISH', + instructions: 'Conversation finished', + team_members: members.join(', ') + } + } + }) + } + + return supervisor + } + + const supervisorAgent = await createTeamSupervisor(llm, supervisorPrompt ? supervisorPrompt : sysPrompt, workersNodeNames) + + const supervisorNode = async (state: ITeamState, config: RunnableConfig) => + await agentNode( + { + state, + agent: supervisorAgent, + abortControllerSignal + }, + config + ) + + const returnOutput: IMultiAgentNode = { + node: supervisorNode, + name: supervisorName ?? 'supervisor', + label: supervisorLabel ?? 'Supervisor', + type: 'supervisor', + workers: workersNodeNames, + recursionLimit, + llm, + moderations, + multiModalMessageContent + } + + return returnOutput + } +} + +async function agentNode( + { state, agent, abortControllerSignal }: { state: ITeamState; agent: AgentExecutor | Runnable; abortControllerSignal: AbortController }, + config: RunnableConfig +) { + try { + if (abortControllerSignal.signal.aborted) { + throw new Error('Aborted!') + } + const result = await agent.invoke({ ...state, signal: abortControllerSignal.signal }, config) + return result + } catch (error) { + throw new Error('Aborted!') + } +} + +const processImageMessage = async ( + index: number, + llm: BaseChatModel, + prompt: ChatPromptTemplate, + nodeData: INodeData, + options: ICommonObject +) => { + let multiModalMessageContent: MessageContentImageUrl[] = [] + + if (llmSupportsVision(llm)) { + const visionChatModel = llm as IVisionChatModal + multiModalMessageContent = await addImagesToMessages(nodeData, options, llm.multiModalOption) + + if (multiModalMessageContent?.length) { + visionChatModel.setVisionModel() + + const msg = HumanMessagePromptTemplate.fromTemplate([...multiModalMessageContent]) + + prompt.promptMessages.splice(index, 0, msg) + } else { + visionChatModel.revertToOriginalModel() + } + } + + return { prompt, multiModalMessageContent } +} + +class RouteTool extends StructuredTool { + name = routerToolName + + description = 'Select the worker to act next' + + schema + + constructor(fields: ICommonObject) { + super() + this.schema = fields.schema + } + + async _call(input: any) { + return JSON.stringify(input) + } +} + +module.exports = { nodeClass: Supervisor_MultiAgents } diff --git a/packages/components/nodes/multiagents/Supervisor/supervisor.svg b/packages/components/nodes/multiagents/Supervisor/supervisor.svg new file mode 100644 index 00000000000..66ade206d1a --- /dev/null +++ b/packages/components/nodes/multiagents/Supervisor/supervisor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/multiagents/Worker/Worker.ts b/packages/components/nodes/multiagents/Worker/Worker.ts new file mode 100644 index 00000000000..ffa4569553f --- /dev/null +++ b/packages/components/nodes/multiagents/Worker/Worker.ts @@ -0,0 +1,291 @@ +import { flatten } from 'lodash' +import { RunnableSequence, RunnablePassthrough, RunnableConfig } from '@langchain/core/runnables' +import { ChatPromptTemplate, MessagesPlaceholder, HumanMessagePromptTemplate } from '@langchain/core/prompts' +import { BaseChatModel } from '@langchain/core/language_models/chat_models' +import { HumanMessage } from '@langchain/core/messages' +import { formatToOpenAIToolMessages } from 'langchain/agents/format_scratchpad/openai_tools' +import { type ToolsAgentStep } from 'langchain/agents/openai/output_parser' +import { INode, INodeData, INodeParams, IMultiAgentNode, ITeamState, ICommonObject, MessageContentImageUrl } from '../../../src/Interface' +import { ToolCallingAgentOutputParser, AgentExecutor } from '../../../src/agents' +import { StringOutputParser } from '@langchain/core/output_parsers' +import { getInputVariables, handleEscapeCharacters } from '../../../src/utils' + +const examplePrompt = 'You are a research assistant who can search for up-to-date info using search engine.' + +class Worker_MultiAgents implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs?: INodeParams[] + badge?: string + + constructor() { + this.label = 'Worker' + this.name = 'worker' + this.version = 1.0 + this.type = 'Worker' + this.icon = 'worker.svg' + this.category = 'Multi Agents' + this.baseClasses = [this.type] + this.inputs = [ + { + label: 'Worker Name', + name: 'workerName', + type: 'string', + placeholder: 'Worker' + }, + { + label: 'Worker Prompt', + name: 'workerPrompt', + type: 'string', + rows: 4, + default: examplePrompt + }, + { + label: 'Tools', + name: 'tools', + type: 'Tool', + list: true, + optional: true + }, + { + label: 'Supervisor', + name: 'supervisor', + type: 'Supervisor' + }, + { + label: 'Tool Calling Chat Model', + name: 'model', + type: 'BaseChatModel', + optional: true, + description: `Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used` + }, + { + label: 'Format Prompt Values', + name: 'promptValues', + type: 'json', + optional: true, + acceptVariable: true, + list: true + }, + { + label: 'Max Iterations', + name: 'maxIterations', + type: 'number', + optional: true + } + ] + } + + async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { + let tools = nodeData.inputs?.tools + tools = flatten(tools) + let workerPrompt = nodeData.inputs?.workerPrompt as string + const workerLabel = nodeData.inputs?.workerName as string + const supervisor = nodeData.inputs?.supervisor as IMultiAgentNode + const maxIterations = nodeData.inputs?.maxIterations as string + const model = nodeData.inputs?.model as BaseChatModel + const promptValuesStr = nodeData.inputs?.promptValues + + if (!workerLabel) throw new Error('Worker name is required!') + const workerName = workerLabel.toLowerCase().replace(/\s/g, '_').trim() + + if (!workerPrompt) throw new Error('Worker prompt is required!') + + let workerInputVariablesValues: ICommonObject = {} + if (promptValuesStr) { + try { + workerInputVariablesValues = typeof promptValuesStr === 'object' ? promptValuesStr : JSON.parse(promptValuesStr) + } catch (exception) { + throw new Error("Invalid JSON in the Worker's Prompt Input Values: " + exception) + } + } + workerInputVariablesValues = handleEscapeCharacters(workerInputVariablesValues, true) + + const llm = model || (supervisor.llm as BaseChatModel) + const multiModalMessageContent = supervisor?.multiModalMessageContent || [] + + const abortControllerSignal = options.signal as AbortController + const workerInputVariables = getInputVariables(workerPrompt) + + if (!workerInputVariables.every((element) => Object.keys(workerInputVariablesValues).includes(element))) { + throw new Error('Worker input variables values are not provided!') + } + + const agent = await createAgent( + llm, + [...tools], + workerPrompt, + multiModalMessageContent, + workerInputVariablesValues, + maxIterations, + { + sessionId: options.sessionId, + chatId: options.chatId, + input + } + ) + + const workerNode = async (state: ITeamState, config: RunnableConfig) => + await agentNode( + { + state, + agent: agent, + name: workerName, + abortControllerSignal + }, + config + ) + + const returnOutput: IMultiAgentNode = { + node: workerNode, + name: workerName, + label: workerLabel, + type: 'worker', + workerPrompt, + workerInputVariables, + parentSupervisorName: supervisor.name ?? 'supervisor' + } + + return returnOutput + } +} + +async function createAgent( + llm: BaseChatModel, + tools: any[], + systemPrompt: string, + multiModalMessageContent: MessageContentImageUrl[], + workerInputVariablesValues: ICommonObject, + maxIterations?: string, + flowObj?: { sessionId?: string; chatId?: string; input?: string } +): Promise { + if (tools.length) { + const combinedPrompt = + systemPrompt + + '\nWork autonomously according to your specialty, using the tools available to you.' + + ' Do not ask for clarification.' + + ' Your other team members (and other teams) will collaborate with you with their own specialties.' + + ' You are chosen for a reason! You are one of the following team members: {team_members}.' + + //const toolNames = tools.length ? tools.map((t) => t.name).join(', ') : '' + const prompt = ChatPromptTemplate.fromMessages([ + ['system', combinedPrompt], + new MessagesPlaceholder('messages'), + new MessagesPlaceholder('agent_scratchpad') + /* Gettind rid of this for now because other LLMs dont support system message at later stage + [ + 'system', + [ + 'Supervisor instructions: {instructions}\n' + tools.length + ? `Remember, you individually can only use these tools: ${toolNames}` + : '' + '\n\nEnd if you have already completed the requested task. Communicate the work completed.' + ].join('\n') + ]*/ + ]) + + if (multiModalMessageContent.length) { + const msg = HumanMessagePromptTemplate.fromTemplate([...multiModalMessageContent]) + prompt.promptMessages.splice(1, 0, msg) + } + + if (llm.bindTools === undefined) { + throw new Error(`This agent only compatible with function calling models.`) + } + const modelWithTools = llm.bindTools(tools) + + const agent = RunnableSequence.from([ + RunnablePassthrough.assign({ + //@ts-ignore + agent_scratchpad: (input: { steps: ToolsAgentStep[] }) => formatToOpenAIToolMessages(input.steps) + }), + RunnablePassthrough.assign(transformObjectPropertyToFunction(workerInputVariablesValues)), + prompt, + modelWithTools, + new ToolCallingAgentOutputParser() + ]) + + const executor = AgentExecutor.fromAgentAndTools({ + agent: agent, + tools, + sessionId: flowObj?.sessionId, + chatId: flowObj?.chatId, + input: flowObj?.input, + verbose: process.env.DEBUG === 'true' ? true : false, + maxIterations: maxIterations ? parseFloat(maxIterations) : undefined + }) + return executor + } else { + const combinedPrompt = + systemPrompt + + '\nWork autonomously according to your specialty, using the tools available to you.' + + ' Do not ask for clarification.' + + ' Your other team members (and other teams) will collaborate with you with their own specialties.' + + ' You are chosen for a reason! You are one of the following team members: {team_members}.' + + const prompt = ChatPromptTemplate.fromMessages([['system', combinedPrompt], new MessagesPlaceholder('messages')]) + if (multiModalMessageContent.length) { + const msg = HumanMessagePromptTemplate.fromTemplate([...multiModalMessageContent]) + prompt.promptMessages.splice(1, 0, msg) + } + const conversationChain = RunnableSequence.from([ + RunnablePassthrough.assign(transformObjectPropertyToFunction(workerInputVariablesValues)), + prompt, + llm, + new StringOutputParser() + ]) + return conversationChain + } +} + +async function agentNode( + { + state, + agent, + name, + abortControllerSignal + }: { state: ITeamState; agent: AgentExecutor | RunnableSequence; name: string; abortControllerSignal: AbortController }, + config: RunnableConfig +) { + try { + if (abortControllerSignal.signal.aborted) { + throw new Error('Aborted!') + } + const result = await agent.invoke({ ...state, signal: abortControllerSignal.signal }, config) + const additional_kwargs: ICommonObject = {} + if (result.usedTools) { + additional_kwargs.usedTools = result.usedTools + } + if (result.sourceDocuments) { + additional_kwargs.sourceDocuments = result.sourceDocuments + } + return { + messages: [ + new HumanMessage({ + content: typeof result === 'string' ? result : result.output, + name, + additional_kwargs: Object.keys(additional_kwargs).length ? additional_kwargs : undefined + }) + ] + } + } catch (error) { + throw new Error('Aborted!') + } +} + +const transformObjectPropertyToFunction = (obj: ICommonObject) => { + const transformedObject: ICommonObject = {} + + for (const key in obj) { + transformedObject[key] = () => obj[key] + } + + return transformedObject +} + +module.exports = { nodeClass: Worker_MultiAgents } diff --git a/packages/components/nodes/multiagents/Worker/worker.svg b/packages/components/nodes/multiagents/Worker/worker.svg new file mode 100644 index 00000000000..671bc020062 --- /dev/null +++ b/packages/components/nodes/multiagents/Worker/worker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/tools/ChatflowTool/ChatflowTool.ts b/packages/components/nodes/tools/ChatflowTool/ChatflowTool.ts new file mode 100644 index 00000000000..a718a0932e7 --- /dev/null +++ b/packages/components/nodes/tools/ChatflowTool/ChatflowTool.ts @@ -0,0 +1,259 @@ +import { DataSource } from 'typeorm' +import { z } from 'zod' +import fetch from 'node-fetch' +import { RunnableConfig } from '@langchain/core/runnables' +import { CallbackManagerForToolRun, Callbacks, CallbackManager, parseCallbackConfigArg } from '@langchain/core/callbacks/manager' +import { StructuredTool } from '@langchain/core/tools' +import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../src/Interface' +import { getCredentialData, getCredentialParam } from '../../../src/utils' + +class ChatflowTool_Tools implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'Chatflow Tool' + this.name = 'ChatflowTool' + this.version = 1.0 + this.type = 'ChatflowTool' + this.icon = 'chatflowTool.svg' + this.category = 'Tools' + this.description = 'Use as a tool to execute another chatflow' + this.baseClasses = [this.type, 'Tool'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['chatflowApi'], + optional: true + } + this.inputs = [ + { + label: 'Select Chatflow', + name: 'selectedChatflow', + type: 'asyncOptions', + loadMethod: 'listChatflows' + }, + { + label: 'Tool Name', + name: 'name', + type: 'string' + }, + { + label: 'Tool Description', + name: 'description', + type: 'string', + description: 'Description of what the tool does. This is for LLM to determine when to use this tool.', + rows: 3, + placeholder: + 'State of the Union QA - useful for when you need to ask questions about the most recent state of the union address.' + }, + { + label: 'Use Question from Chat', + name: 'useQuestionFromChat', + type: 'boolean', + description: + 'Whether to use the question from the chat as input to the chatflow. If turned on, this will override the custom input.', + optional: true, + additionalParams: true + }, + { + label: 'Custom Input', + name: 'customInput', + type: 'string', + description: 'Custom input to be passed to the chatflow. Leave empty to let LLM decides the input.', + optional: true, + additionalParams: true + } + ] + } + + //@ts-ignore + loadMethods = { + async listChatflows(_: INodeData, options: ICommonObject): Promise { + const returnData: INodeOptionsValue[] = [] + + const appDataSource = options.appDataSource as DataSource + const databaseEntities = options.databaseEntities as IDatabaseEntity + if (appDataSource === undefined || !appDataSource) { + return returnData + } + + const chatflows = await appDataSource.getRepository(databaseEntities['ChatFlow']).find() + + for (let i = 0; i < chatflows.length; i += 1) { + const data = { + label: chatflows[i].name, + name: chatflows[i].id + } as INodeOptionsValue + returnData.push(data) + } + return returnData + } + } + + async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { + const selectedChatflowId = nodeData.inputs?.selectedChatflow as string + const _name = nodeData.inputs?.name as string + const description = nodeData.inputs?.description as string + const useQuestionFromChat = nodeData.inputs?.useQuestionFromChat as boolean + const customInput = nodeData.inputs?.customInput as string + + const baseURL = options.baseURL as string + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const chatflowApiKey = getCredentialParam('chatflowApiKey', credentialData, nodeData) + + let headers = {} + if (chatflowApiKey) headers = { Authorization: `Bearer ${chatflowApiKey}` } + + let toolInput = '' + if (useQuestionFromChat) { + toolInput = input + } else if (!customInput) { + toolInput = customInput + } + + let name = _name || 'chatflow_tool' + + return new ChatflowTool({ name, baseURL, description, chatflowid: selectedChatflowId, headers, input: toolInput }) + } +} + +class ChatflowTool extends StructuredTool { + static lc_name() { + return 'ChatflowTool' + } + + name = 'chatflow_tool' + + description = 'Execute another chatflow' + + input = '' + + chatflowid = '' + + baseURL = 'http://localhost:3000' + + headers = {} + + schema = z.object({ + input: z.string().describe('input question') + }) + + constructor({ + name, + description, + input, + chatflowid, + baseURL, + headers + }: { + name: string + description: string + input: string + chatflowid: string + baseURL: string + headers: ICommonObject + }) { + super() + this.name = name + this.description = description + this.input = input + this.baseURL = baseURL + this.headers = headers + this.chatflowid = chatflowid + } + + async call( + arg: z.infer, + configArg?: RunnableConfig | Callbacks, + tags?: string[], + flowConfig?: { sessionId?: string; chatId?: string; input?: string } + ): Promise { + const config = parseCallbackConfigArg(configArg) + if (config.runName === undefined) { + config.runName = this.name + } + let parsed + try { + parsed = await this.schema.parseAsync(arg) + } catch (e) { + throw new Error(`Received tool input did not match expected schema: ${JSON.stringify(arg)}`) + } + const callbackManager_ = await CallbackManager.configure( + config.callbacks, + this.callbacks, + config.tags || tags, + this.tags, + config.metadata, + this.metadata, + { verbose: this.verbose } + ) + const runManager = await callbackManager_?.handleToolStart( + this.toJSON(), + typeof parsed === 'string' ? parsed : JSON.stringify(parsed), + undefined, + undefined, + undefined, + undefined, + config.runName + ) + let result + try { + result = await this._call(parsed, runManager, flowConfig) + } catch (e) { + await runManager?.handleToolError(e) + throw e + } + await runManager?.handleToolEnd(result) + return result + } + + // @ts-ignore + protected async _call( + arg: z.infer, + _?: CallbackManagerForToolRun, + flowConfig?: { sessionId?: string; chatId?: string; input?: string } + ): Promise { + const inputQuestion = this.input || arg.input + + const url = `${this.baseURL}/api/v1/prediction/${this.chatflowid}` + + const body = { + question: inputQuestion, + chatId: flowConfig?.chatId, + overrideConfig: { + sessionId: flowConfig?.sessionId + } + } + + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...this.headers + }, + body: JSON.stringify(body) + } + + try { + const response = await fetch(url, options) + const resp = await response.json() + return resp.text || '' + } catch (error) { + console.error(error) + return '' + } + } +} + +module.exports = { nodeClass: ChatflowTool_Tools } diff --git a/packages/components/nodes/tools/ChatflowTool/chatflowTool.svg b/packages/components/nodes/tools/ChatflowTool/chatflowTool.svg new file mode 100644 index 00000000000..d61683d74a5 --- /dev/null +++ b/packages/components/nodes/tools/ChatflowTool/chatflowTool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/tools/E2B/E2B.ts b/packages/components/nodes/tools/E2B/E2B.ts new file mode 100644 index 00000000000..1245ddf5006 --- /dev/null +++ b/packages/components/nodes/tools/E2B/E2B.ts @@ -0,0 +1,152 @@ +/* +* TODO: Implement codeInterpreter column to chat_message table +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { StructuredTool, ToolParams } from '@langchain/core/tools' +import { CodeInterpreter } from '@e2b/code-interpreter' +import { z } from 'zod' + +const DESC = `Evaluates python code in a sandbox environment. \ +The environment is long running and exists across multiple executions. \ +You must send the whole script every time and print your outputs. \ +Script should be pure python code that can be evaluated. \ +It should be in python format NOT markdown. \ +The code should NOT be wrapped in backticks. \ +All python packages including requests, matplotlib, scipy, numpy, pandas, \ +etc are available. Create and display chart using "plt.show()".` +const NAME = 'code_interpreter' + +class E2B_Tools implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + badge: string + credential: INodeParams + + constructor() { + this.label = 'E2B' + this.name = 'e2b' + this.version = 1.0 + this.type = 'E2B' + this.icon = 'e2b.png' + this.category = 'Tools' + this.badge = 'NEW' + this.description = 'Execute code in E2B Code Intepreter' + this.baseClasses = [this.type, 'Tool', ...getBaseClasses(E2BTool)] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['E2BApi'] + } + this.inputs = [ + { + label: 'Tool Name', + name: 'toolName', + type: 'string', + description: 'Specify the name of the tool', + default: 'code_interpreter' + }, + { + label: 'Tool Description', + name: 'toolDesc', + type: 'string', + rows: 4, + description: 'Specify the description of the tool', + default: DESC + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const toolDesc = nodeData.inputs?.toolDesc as string + const toolName = nodeData.inputs?.toolName as string + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const e2bApiKey = getCredentialParam('e2bApiKey', credentialData, nodeData) + const socketIO = options.socketIO + const socketIOClientId = options.socketIOClientId + + return await E2BTool.initialize({ + description: toolDesc ?? DESC, + name: toolName ?? NAME, + apiKey: e2bApiKey, + schema: z.object({ + input: z.string().describe('Python code to be executed in the sandbox environment') + }), + socketIO, + socketIOClientId + }) + } +} + +type E2BToolParams = ToolParams & { instance: CodeInterpreter } + +export class E2BTool extends StructuredTool { + static lc_name() { + return 'E2BTool' + } + + name = NAME + + description = DESC + + instance: CodeInterpreter + + apiKey: string + + schema + + socketIO + + socketIOClientId = '' + + constructor(options: E2BToolParams & { name: string; description: string, apiKey: string, schema: any, socketIO: any, socketIOClientId: string}) { + super(options) + this.instance = options.instance + this.description = options.description + this.name = options.name + this.apiKey = options.apiKey + this.schema = options.schema + this.returnDirect = true + this.socketIO = options.socketIO + this.socketIOClientId = options.socketIOClientId + } + + static async initialize(options: Partial & { name: string; description: string, apiKey: string, schema: any, socketIO: any, socketIOClientId: string }) { + const instance = await CodeInterpreter.create({ apiKey: options.apiKey }) + return new this({ instance, name: options.name, description: options.description, apiKey: options.apiKey, schema: options.schema, socketIO: options.socketIO, socketIOClientId: options.socketIOClientId}) + } + + async _call(args: any) { + try { + if ('input' in args) { + const execution = await this.instance.notebook.execCell(args?.input) + let imgHTML = '' + for (const result of execution.results) { + if (result.png) { + imgHTML += `\n\nimage
` + } + if (result.jpeg) { + imgHTML += `\n\nimage
` + } + } + const output = execution.text ? execution.text + imgHTML : imgHTML + if (this.socketIO && this.socketIOClientId) this.socketIO.to(this.socketIOClientId).emit('token', output) + return output + } else { + return 'No input provided' + } + } catch (e) { + return typeof e === 'string' ? e : JSON.stringify(e, null, 2) + } + } +} + +module.exports = { nodeClass: E2B_Tools } +*/ diff --git a/packages/components/nodes/tools/E2B/e2b.png b/packages/components/nodes/tools/E2B/e2b.png new file mode 100644 index 00000000000..1b24b58e381 Binary files /dev/null and b/packages/components/nodes/tools/E2B/e2b.png differ diff --git a/packages/components/nodes/tools/PythonInterpreter/PythonInterpreter.ts b/packages/components/nodes/tools/PythonInterpreter/PythonInterpreter.ts new file mode 100644 index 00000000000..08f87738546 --- /dev/null +++ b/packages/components/nodes/tools/PythonInterpreter/PythonInterpreter.ts @@ -0,0 +1,128 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import { loadPyodide, type PyodideInterface } from 'pyodide' +import { Tool, ToolParams } from '@langchain/core/tools' +import * as path from 'path' +import { getUserHome } from '../../../src/utils' + +let pyodideInstance: PyodideInterface | undefined +const DESC = `Evaluates python code in a sandbox environment. The environment resets on every execution. You must send the whole script every time and print your outputs. Script should be pure python code that can be evaluated. Use only packages available in Pyodide.` +const NAME = 'python_interpreter' + +async function LoadPyodide(): Promise { + if (pyodideInstance === undefined) { + const obj = { packageCacheDir: path.join(getUserHome(), '.flowise', 'pyodideCacheDir') } + pyodideInstance = await loadPyodide(obj) + } + return pyodideInstance +} + +class PythonInterpreter_Tools implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + badge: string + + constructor() { + this.label = 'Python Interpreter' + this.name = 'pythonInterpreter' + this.version = 1.0 + this.type = 'PythonInterpreter' + this.icon = 'python.svg' + this.category = 'Tools' + this.badge = 'NEW' + this.description = 'Execute python code in Pyodide sandbox environment' + this.baseClasses = [this.type, 'Tool', ...getBaseClasses(PythonInterpreterTool)] + this.inputs = [ + { + label: 'Tool Name', + name: 'toolName', + type: 'string', + description: 'Specify the name of the tool', + default: 'python_interpreter' + }, + { + label: 'Tool Description', + name: 'toolDesc', + type: 'string', + rows: 4, + description: 'Specify the description of the tool', + default: DESC + } + ] + } + + async init(nodeData: INodeData): Promise { + const toolDesc = nodeData.inputs?.toolDesc as string + const toolName = nodeData.inputs?.toolName as string + + return await PythonInterpreterTool.initialize({ + description: toolDesc ?? DESC, + name: toolName ?? NAME + }) + } +} + +type PythonInterpreterToolParams = Parameters[0] & + ToolParams & { + instance: PyodideInterface + } + +export class PythonInterpreterTool extends Tool { + static lc_name() { + return 'PythonInterpreterTool' + } + + name = NAME + + description = DESC + + pyodideInstance: PyodideInterface + + stdout = '' + + stderr = '' + + constructor(options: PythonInterpreterToolParams & { name: string; description: string }) { + super(options) + this.description = options.description + this.name = options.name + this.pyodideInstance = options.instance + this.pyodideInstance.setStderr({ + batched: (text: string) => { + this.stderr += text + } + }) + this.pyodideInstance.setStdout({ + batched: (text: string) => { + this.stdout += text + } + }) + } + + static async initialize(options: Partial & { name: string; description: string }) { + const instance = await LoadPyodide() + return new this({ instance, name: options.name, description: options.description }) + } + + async _call(script: string) { + this.stdout = '' + this.stderr = '' + + try { + await this.pyodideInstance.loadPackagesFromImports(script) + await this.pyodideInstance.runPythonAsync(script) + return JSON.stringify({ stdout: this.stdout, stderr: this.stderr }, null, 2) + } catch (e) { + return typeof e === 'string' ? e : JSON.stringify(e, null, 2) + } + } +} + +module.exports = { nodeClass: PythonInterpreter_Tools } diff --git a/packages/components/nodes/tools/PythonInterpreter/python.svg b/packages/components/nodes/tools/PythonInterpreter/python.svg new file mode 100644 index 00000000000..9cbbf9478df --- /dev/null +++ b/packages/components/nodes/tools/PythonInterpreter/python.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/tools/RequestsGet/RequestsGet.ts b/packages/components/nodes/tools/RequestsGet/RequestsGet.ts deleted file mode 100644 index 91cff5000bb..00000000000 --- a/packages/components/nodes/tools/RequestsGet/RequestsGet.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' -import { getBaseClasses } from '../../../src/utils' -import { desc, RequestParameters, RequestsGetTool } from './core' - -class RequestsGet_Tools implements INode { - label: string - name: string - version: number - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - - constructor() { - this.label = 'Requests Get' - this.name = 'requestsGet' - this.version = 1.0 - this.type = 'RequestsGet' - this.icon = 'requestsget.svg' - this.category = 'Tools' - this.description = 'Execute HTTP GET requests' - this.baseClasses = [this.type, ...getBaseClasses(RequestsGetTool)] - this.inputs = [ - { - label: 'URL', - name: 'url', - type: 'string', - description: - 'Agent will make call to this exact URL. If not specified, agent will try to figure out itself from AIPlugin if provided', - additionalParams: true, - optional: true - }, - { - label: 'Description', - name: 'description', - type: 'string', - rows: 4, - default: desc, - description: 'Acts like a prompt to tell agent when it should use this tool', - additionalParams: true, - optional: true - }, - { - label: 'Headers', - name: 'headers', - type: 'json', - additionalParams: true, - optional: true - } - ] - } - - async init(nodeData: INodeData): Promise { - const headers = nodeData.inputs?.headers as string - const url = nodeData.inputs?.url as string - const description = nodeData.inputs?.description as string - - const obj: RequestParameters = {} - if (url) obj.url = url - if (description) obj.description = description - if (headers) { - const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(headers) - obj.headers = parsedHeaders - } - - return new RequestsGetTool(obj) - } -} - -module.exports = { nodeClass: RequestsGet_Tools } diff --git a/packages/components/nodes/tools/RequestsGet/core.ts b/packages/components/nodes/tools/RequestsGet/core.ts deleted file mode 100644 index ea97cdf2269..00000000000 --- a/packages/components/nodes/tools/RequestsGet/core.ts +++ /dev/null @@ -1,46 +0,0 @@ -import fetch from 'node-fetch' -import { Tool } from '@langchain/core/tools' - -export const desc = `A portal to the internet. Use this when you need to get specific content from a website. -Input should be a url (i.e. https://www.google.com). The output will be the text response of the GET request.` - -export interface Headers { - [key: string]: string -} - -export interface RequestParameters { - headers?: Headers - url?: string - description?: string - maxOutputLength?: number -} - -export class RequestsGetTool extends Tool { - name = 'requests_get' - url = '' - description = desc - maxOutputLength = 2000 - headers = {} - - constructor(args?: RequestParameters) { - super() - this.url = args?.url ?? this.url - this.headers = args?.headers ?? this.headers - this.description = args?.description ?? this.description - this.maxOutputLength = args?.maxOutputLength ?? this.maxOutputLength - } - - /** @ignore */ - async _call(input: string) { - const inputUrl = !this.url ? input : this.url - - if (process.env.DEBUG === 'true') console.info(`Making GET API call to ${inputUrl}`) - - const res = await fetch(inputUrl, { - headers: this.headers - }) - - const text = await res.text() - return text.slice(0, this.maxOutputLength) - } -} diff --git a/packages/components/nodes/tools/RequestsGet/requestsget.svg b/packages/components/nodes/tools/RequestsGet/requestsget.svg deleted file mode 100644 index d92c5b51a93..00000000000 --- a/packages/components/nodes/tools/RequestsGet/requestsget.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/components/nodes/tools/RequestsPost/RequestsPost.ts b/packages/components/nodes/tools/RequestsPost/RequestsPost.ts deleted file mode 100644 index 9ff3d1426c9..00000000000 --- a/packages/components/nodes/tools/RequestsPost/RequestsPost.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' -import { getBaseClasses } from '../../../src/utils' -import { RequestParameters, desc, RequestsPostTool } from './core' - -class RequestsPost_Tools implements INode { - label: string - name: string - version: number - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - - constructor() { - this.label = 'Requests Post' - this.name = 'requestsPost' - this.version = 1.0 - this.type = 'RequestsPost' - this.icon = 'requestspost.svg' - this.category = 'Tools' - this.description = 'Execute HTTP POST requests' - this.baseClasses = [this.type, ...getBaseClasses(RequestsPostTool)] - this.inputs = [ - { - label: 'URL', - name: 'url', - type: 'string', - description: - 'Agent will make call to this exact URL. If not specified, agent will try to figure out itself from AIPlugin if provided', - additionalParams: true, - optional: true - }, - { - label: 'Body', - name: 'body', - type: 'json', - description: - 'JSON body for the POST request. If not specified, agent will try to figure out itself from AIPlugin if provided', - additionalParams: true, - optional: true - }, - { - label: 'Description', - name: 'description', - type: 'string', - rows: 4, - default: desc, - description: 'Acts like a prompt to tell agent when it should use this tool', - additionalParams: true, - optional: true - }, - { - label: 'Headers', - name: 'headers', - type: 'json', - additionalParams: true, - optional: true - } - ] - } - - async init(nodeData: INodeData): Promise { - const headers = nodeData.inputs?.headers as string - const url = nodeData.inputs?.url as string - const description = nodeData.inputs?.description as string - const body = nodeData.inputs?.body as string - - const obj: RequestParameters = {} - if (url) obj.url = url - if (description) obj.description = description - if (headers) { - const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(headers) - obj.headers = parsedHeaders - } - if (body) { - const parsedBody = typeof body === 'object' ? body : JSON.parse(body) - obj.body = parsedBody - } - - return new RequestsPostTool(obj) - } -} - -module.exports = { nodeClass: RequestsPost_Tools } diff --git a/packages/components/nodes/tools/RequestsPost/core.ts b/packages/components/nodes/tools/RequestsPost/core.ts deleted file mode 100644 index a380f1676f8..00000000000 --- a/packages/components/nodes/tools/RequestsPost/core.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Tool } from '@langchain/core/tools' -import fetch from 'node-fetch' - -export const desc = `Use this when you want to POST to a website. -Input should be a json string with two keys: "url" and "data". -The value of "url" should be a string, and the value of "data" should be a dictionary of -key-value pairs you want to POST to the url as a JSON body. -Be careful to always use double quotes for strings in the json string -The output will be the text response of the POST request.` - -export interface Headers { - [key: string]: string -} - -export interface Body { - [key: string]: any -} - -export interface RequestParameters { - headers?: Headers - body?: Body - url?: string - description?: string - maxOutputLength?: number -} - -export class RequestsPostTool extends Tool { - name = 'requests_post' - url = '' - description = desc - maxOutputLength = Infinity - headers = {} - body = {} - - constructor(args?: RequestParameters) { - super() - this.url = args?.url ?? this.url - this.headers = args?.headers ?? this.headers - this.body = args?.body ?? this.body - this.description = args?.description ?? this.description - this.maxOutputLength = args?.maxOutputLength ?? this.maxOutputLength - } - - /** @ignore */ - async _call(input: string) { - try { - let inputUrl = '' - let inputBody = {} - if (Object.keys(this.body).length || this.url) { - if (this.url) inputUrl = this.url - if (Object.keys(this.body).length) inputBody = this.body - } else { - const { url, data } = JSON.parse(input) - inputUrl = url - inputBody = data - } - - if (process.env.DEBUG === 'true') console.info(`Making POST API call to ${inputUrl} with body ${JSON.stringify(inputBody)}`) - - const res = await fetch(inputUrl, { - method: 'POST', - headers: this.headers, - body: JSON.stringify(inputBody) - }) - - const text = await res.text() - return text.slice(0, this.maxOutputLength) - } catch (error) { - return `${error}` - } - } -} diff --git a/packages/components/nodes/tools/RequestsPost/requestspost.svg b/packages/components/nodes/tools/RequestsPost/requestspost.svg deleted file mode 100644 index 477b1baf3d4..00000000000 --- a/packages/components/nodes/tools/RequestsPost/requestspost.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/components/nodes/vectorstores/Supabase/Supabase.ts b/packages/components/nodes/vectorstores/Supabase/Supabase.ts index c732f286f5f..5e76f47a85b 100644 --- a/packages/components/nodes/vectorstores/Supabase/Supabase.ts +++ b/packages/components/nodes/vectorstores/Supabase/Supabase.ts @@ -2,7 +2,7 @@ import { flatten } from 'lodash' import { createClient } from '@supabase/supabase-js' import { Document } from '@langchain/core/documents' import { Embeddings } from '@langchain/core/embeddings' -import { SupabaseVectorStore, SupabaseLibArgs } from '@langchain/community/vectorstores/supabase' +import { SupabaseVectorStore, SupabaseLibArgs, SupabaseFilterRPCCall } from '@langchain/community/vectorstores/supabase' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams, IndexingResult } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' @@ -25,7 +25,7 @@ class Supabase_VectorStores implements INode { constructor() { this.label = 'Supabase' this.name = 'supabase' - this.version = 3.0 + this.version = 4.0 this.type = 'Supabase' this.icon = 'supabase.svg' this.category = 'Vector Stores' @@ -80,6 +80,19 @@ class Supabase_VectorStores implements INode { optional: true, additionalParams: true }, + { + label: 'Supabase RPC Filter', + name: 'supabaseRPCFilter', + type: 'string', + rows: 4, + placeholder: `filter("metadata->a::int", "gt", 5) +.filter("metadata->c::int", "gt", 7) +.filter("metadata->>stuff", "eq", "right");`, + description: + 'Query builder-style filtering. If this is set, will override the metadata filter. Refer here for more information', + optional: true, + additionalParams: true + }, { label: 'Top K', name: 'topK', @@ -167,6 +180,7 @@ class Supabase_VectorStores implements INode { const queryName = nodeData.inputs?.queryName as string const embeddings = nodeData.inputs?.embeddings as Embeddings const supabaseMetadataFilter = nodeData.inputs?.supabaseMetadataFilter + const supabaseRPCFilter = nodeData.inputs?.supabaseRPCFilter const credentialData = await getCredentialData(nodeData.credential ?? '', options) const supabaseApiKey = getCredentialParam('supabaseApiKey', credentialData, nodeData) @@ -184,6 +198,14 @@ class Supabase_VectorStores implements INode { obj.filter = metadatafilter } + if (supabaseRPCFilter) { + const funcString = `return rpc.${supabaseRPCFilter};` + const funcFilter = new Function('rpc', funcString) + obj.filter = (rpc: SupabaseFilterRPCCall) => { + return funcFilter(rpc) + } + } + const vectorStore = await SupabaseVectorStore.fromExistingIndex(embeddings, obj) return resolveVectorStoreOrRetriever(nodeData, vectorStore, obj.filter) diff --git a/packages/components/package.json b/packages/components/package.json index 9c64c4afb5e..83d739377a0 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.7.1", + "version": "1.7.2", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", @@ -25,6 +25,7 @@ "@aws-sdk/client-s3": "^3.427.0", "@datastax/astra-db-ts": "^0.1.2", "@dqbd/tiktoken": "^1.0.7", + "@e2b/code-interpreter": "^0.0.5", "@elastic/elasticsearch": "^8.9.0", "@getzep/zep-cloud": "npm:@getzep/zep-js@next", "@getzep/zep-js": "^0.9.0", @@ -36,13 +37,14 @@ "@langchain/anthropic": "^0.1.14", "@langchain/cohere": "^0.0.7", "@langchain/community": "^0.0.43", - "@langchain/core": "^0.1.57", + "@langchain/core": "^0.1.63", "@langchain/google-genai": "^0.0.10", "@langchain/google-vertexai": "^0.0.5", "@langchain/groq": "^0.0.8", + "@langchain/langgraph": "^0.0.12", "@langchain/mistralai": "^0.0.19", "@langchain/mongodb": "^0.0.1", - "@langchain/openai": "^0.0.28", + "@langchain/openai": "^0.0.30", "@langchain/pinecone": "^0.0.3", "@langchain/weaviate": "^0.0.1", "@mistralai/mistralai": "0.1.3", @@ -76,7 +78,7 @@ "ioredis": "^5.3.2", "jsdom": "^22.1.0", "jsonpointer": "^5.0.1", - "langchain": "^0.1.33", + "langchain": "^0.1.37", "langfuse": "3.3.4", "langfuse-langchain": "^3.3.4", "langsmith": "0.1.6", diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index b2a7d210267..29ee349944d 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -1,3 +1,7 @@ +import { BaseMessage } from '@langchain/core/messages' +import { BufferMemory, BufferWindowMemory, ConversationSummaryMemory, ConversationSummaryBufferMemory } from 'langchain/memory' +import { Moderation } from '../nodes/moderation/Moderation' + /** * Types */ @@ -149,6 +153,38 @@ export interface IUsedTool { toolOutput: string | object } +export interface IMultiAgentNode { + node: any + name: string + label: string + type: 'supervisor' | 'worker' + llm?: any + parentSupervisorName?: string + workers?: string[] + workerPrompt?: string + workerInputVariables?: string[] + recursionLimit?: number + moderations?: Moderation[] + multiModalMessageContent?: MessageContentImageUrl[] +} + +export interface ITeamState { + messages: { + value: (x: BaseMessage[], y: BaseMessage[]) => BaseMessage[] + default: () => BaseMessage[] + } + team_members: string[] + next: string + instructions: string +} + +export interface IAgentReasoning { + agentName: string + messages: string[] + next: string + instructions: string +} + export interface IFileUpload { data?: string type: string @@ -239,35 +275,53 @@ export class VectorStoreRetriever { /** * Implement abstract classes and interface for memory */ -import { BaseMessage } from '@langchain/core/messages' -import { BufferMemory, BufferWindowMemory, ConversationSummaryMemory, ConversationSummaryBufferMemory } from 'langchain/memory' export interface MemoryMethods { - getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise + getChatMessages( + overrideSessionId?: string, + returnBaseMessages?: boolean, + prependMessages?: IMessage[] + ): Promise addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise clearChatMessages(overrideSessionId?: string): Promise } export abstract class FlowiseMemory extends BufferMemory implements MemoryMethods { - abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise + abstract getChatMessages( + overrideSessionId?: string, + returnBaseMessages?: boolean, + prependMessages?: IMessage[] + ): Promise abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise abstract clearChatMessages(overrideSessionId?: string): Promise } export abstract class FlowiseWindowMemory extends BufferWindowMemory implements MemoryMethods { - abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise + abstract getChatMessages( + overrideSessionId?: string, + returnBaseMessages?: boolean, + prependMessages?: IMessage[] + ): Promise abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise abstract clearChatMessages(overrideSessionId?: string): Promise } export abstract class FlowiseSummaryMemory extends ConversationSummaryMemory implements MemoryMethods { - abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise + abstract getChatMessages( + overrideSessionId?: string, + returnBaseMessages?: boolean, + prependMessages?: IMessage[] + ): Promise abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise abstract clearChatMessages(overrideSessionId?: string): Promise } export abstract class FlowiseSummaryBufferMemory extends ConversationSummaryBufferMemory implements MemoryMethods { - abstract getChatMessages(overrideSessionId?: string, returnBaseMessages?: boolean): Promise + abstract getChatMessages( + overrideSessionId?: string, + returnBaseMessages?: boolean, + prependMessages?: IMessage[] + ): Promise abstract addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId?: string): Promise abstract clearChatMessages(overrideSessionId?: string): Promise } diff --git a/packages/components/src/agents.ts b/packages/components/src/agents.ts index 048bf96fdee..ef3acfd9657 100644 --- a/packages/components/src/agents.ts +++ b/packages/components/src/agents.ts @@ -3,7 +3,7 @@ import { ChainValues } from '@langchain/core/utils/types' import { AgentStep, AgentAction } from '@langchain/core/agents' import { BaseMessage, FunctionMessage, AIMessage, isBaseMessage } from '@langchain/core/messages' import { ToolCall } from '@langchain/core/messages/tool' -import { OutputParserException, BaseOutputParser } from '@langchain/core/output_parsers' +import { OutputParserException, BaseOutputParser, BaseLLMOutputParser } from '@langchain/core/output_parsers' import { BaseLanguageModel } from '@langchain/core/language_models/base' import { CallbackManager, CallbackManagerForChainRun, Callbacks } from '@langchain/core/callbacks/manager' import { ToolInputParsingException, Tool, StructuredToolInterface } from '@langchain/core/tools' @@ -25,12 +25,11 @@ import { formatLogToString } from 'langchain/agents/format_scratchpad/log' import { IUsedTool } from './Interface' export const SOURCE_DOCUMENTS_PREFIX = '\n\n----FLOWISE_SOURCE_DOCUMENTS----\n\n' -type AgentFinish = { +export type AgentFinish = { returnValues: Record log: string } type AgentExecutorOutput = ChainValues - interface AgentExecutorIteratorInput { agentExecutor: AgentExecutor inputs: Record @@ -351,7 +350,6 @@ export class AgentExecutor extends BaseChain { const additional = await this.agent.prepareForOutput(returnValues, steps) if (sourceDocuments.length) additional.sourceDocuments = flatten(sourceDocuments) if (usedTools.length) additional.usedTools = usedTools - if (this.returnIntermediateSteps) { return { ...returnValues, intermediateSteps: steps, ...additional } } @@ -829,7 +827,7 @@ export class XMLAgentOutputParser extends AgentActionOutputParser { abstract class AgentMultiActionOutputParser extends BaseOutputParser {} -type ToolsAgentAction = AgentAction & { +export type ToolsAgentAction = AgentAction & { toolCallId: string messageLog?: BaseMessage[] } @@ -898,3 +896,106 @@ export class ToolCallingAgentOutputParser extends AgentMultiActionOutputParser { throw new Error('getFormatInstructions not implemented inside ToolCallingAgentOutputParser.') } } + +export type ParsedToolCall = { + id?: string + + type: string + + args: Record + + /** @deprecated Use `type` instead. Will be removed in 0.2.0. */ + name: string + + /** @deprecated Use `args` instead. Will be removed in 0.2.0. */ + arguments: Record +} + +export type JsonOutputToolsParserParams = { + /** Whether to return the tool call id. */ + returnId?: boolean +} + +export class JsonOutputToolsParser extends BaseLLMOutputParser { + static lc_name() { + return 'JsonOutputToolsParser' + } + + returnId = false + + lc_namespace = ['langchain', 'output_parsers', 'openai_tools'] + + lc_serializable = true + + constructor(fields?: JsonOutputToolsParserParams) { + super(fields) + this.returnId = fields?.returnId ?? this.returnId + } + + /** + * Parses the output and returns a JSON object. If `argsOnly` is true, + * only the arguments of the function call are returned. + * @param generations The output of the LLM to parse. + * @returns A JSON object representation of the function call or its arguments. + */ + async parseResult(generations: ChatGeneration[]): Promise { + const toolCalls = generations[0].message.additional_kwargs.tool_calls + const parsedToolCalls = [] + + if (!toolCalls) { + // @ts-expect-error name and arguemnts are defined by Object.defineProperty + const parsedToolCall: ParsedToolCall = { + type: 'undefined', + args: {} + } + + // backward-compatibility with previous + // versions of Langchain JS, which uses `name` and `arguments` + Object.defineProperty(parsedToolCall, 'name', { + get() { + return this.type + } + }) + + Object.defineProperty(parsedToolCall, 'arguments', { + get() { + return this.args + } + }) + + parsedToolCalls.push(parsedToolCall) + } + + const clonedToolCalls = JSON.parse(JSON.stringify(toolCalls)) + for (const toolCall of clonedToolCalls) { + if (toolCall.function !== undefined) { + // @ts-expect-error name and arguemnts are defined by Object.defineProperty + const parsedToolCall: ParsedToolCall = { + type: toolCall.function.name, + args: JSON.parse(toolCall.function.arguments) + } + + if (this.returnId) { + parsedToolCall.id = toolCall.id + } + + // backward-compatibility with previous + // versions of Langchain JS, which uses `name` and `arguments` + Object.defineProperty(parsedToolCall, 'name', { + get() { + return this.type + } + }) + + Object.defineProperty(parsedToolCall, 'arguments', { + get() { + return this.args + } + }) + + parsedToolCalls.push(parsedToolCall) + } + } + return parsedToolCalls + } +} diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 19b3cbe664d..fcdb83c887e 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -195,7 +195,7 @@ export class CustomChainHandler extends BaseCallbackHandler { Callback Order is "Chain Start -> Chain End" for cached responses. */ if (this.cachedResponse && parentRunId === undefined) { - const cachedValue = outputs.text ?? outputs.response ?? outputs.output ?? outputs.output_text + 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) => { diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index fb556163dc5..d47075018ea 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -8,3 +8,4 @@ export * from './Interface' export * from './utils' export * from './speechToText' export * from './storageUtils' +export * from './handler' diff --git a/packages/components/src/modelLoader.ts b/packages/components/src/modelLoader.ts index e697045dd4b..dca4cdbf94c 100644 --- a/packages/components/src/modelLoader.ts +++ b/packages/components/src/modelLoader.ts @@ -1,5 +1,7 @@ import { INodeOptionsValue } from './Interface' import axios from 'axios' +import * as fs from 'fs' +import * as path from 'path' const MASTER_MODEL_LIST = 'https://raw.githubusercontent.com/FlowiseAI/Flowise/main/packages/components/models.json' @@ -9,15 +11,38 @@ export enum MODEL_TYPE { EMBEDDING = 'embedding' } +const getModelsJSONPath = (): string => { + const checkModelsPaths = [path.join(__dirname, '..', 'models.json'), path.join(__dirname, '..', '..', 'models.json')] + for (const checkPath of checkModelsPaths) { + if (fs.existsSync(checkPath)) { + return checkPath + } + } + return '' +} + const getModelConfig = async (category: MODEL_TYPE, name: string) => { const modelFile = process.env.MODEL_LIST_CONFIG_JSON || MASTER_MODEL_LIST if (!modelFile) { throw new Error('MODEL_LIST_CONFIG_JSON not set') } - const resp = await axios.get(modelFile) - const models = resp.data - const categoryModels = models[category] - return categoryModels.find((model: any) => model.name === name) + try { + const resp = await axios.get(modelFile) + if (resp.status === 200 && resp.data) { + const models = resp.data + const categoryModels = models[category] + return categoryModels.find((model: INodeOptionsValue) => model.name === name) + } else { + throw new Error('Error fetching model list') + } + } catch (e) { + const models = await fs.promises.readFile(getModelsJSONPath(), 'utf8') + if (models) { + const categoryModels = JSON.parse(models)[category] + return categoryModels.find((model: INodeOptionsValue) => model.name === name) + } + return {} + } } export const getModels = async (category: MODEL_TYPE, name: string) => { diff --git a/packages/components/src/speechToText.ts b/packages/components/src/speechToText.ts index 732b574c883..1b952913088 100644 --- a/packages/components/src/speechToText.ts +++ b/packages/components/src/speechToText.ts @@ -4,40 +4,69 @@ import { type ClientOptions, OpenAIClient } from '@langchain/openai' import { AssemblyAI } from 'assemblyai' import { getFileFromStorage } from './storageUtils' +const SpeechToTextType = { + OPENAI_WHISPER: 'openAIWhisper', + ASSEMBLYAI_TRANSCRIBE: 'assemblyAiTranscribe', + LOCALAI_STT: 'localAISTT' +} + export const convertSpeechToText = async (upload: IFileUpload, speechToTextConfig: ICommonObject, options: ICommonObject) => { if (speechToTextConfig) { const credentialId = speechToTextConfig.credentialId as string const credentialData = await getCredentialData(credentialId ?? '', options) const audio_file = await getFileFromStorage(upload.name, options.chatflowid, options.chatId) - if (speechToTextConfig.name === 'openAIWhisper') { - const openAIClientOptions: ClientOptions = { - apiKey: credentialData.openAIApiKey - } - const openAIClient = new OpenAIClient(openAIClientOptions) - const transcription = await openAIClient.audio.transcriptions.create({ - file: new File([new Blob([audio_file])], upload.name), - model: 'whisper-1', - language: speechToTextConfig?.language, - temperature: speechToTextConfig?.temperature ? parseFloat(speechToTextConfig.temperature) : undefined, - prompt: speechToTextConfig?.prompt - }) - if (transcription?.text) { - return transcription.text + switch (speechToTextConfig.name) { + case SpeechToTextType.OPENAI_WHISPER: { + const openAIClientOptions: ClientOptions = { + apiKey: credentialData.openAIApiKey + } + const openAIClient = new OpenAIClient(openAIClientOptions) + const openAITranscription = await openAIClient.audio.transcriptions.create({ + file: new File([new Blob([audio_file])], upload.name), + model: 'whisper-1', + language: speechToTextConfig?.language, + temperature: speechToTextConfig?.temperature ? parseFloat(speechToTextConfig.temperature) : undefined, + prompt: speechToTextConfig?.prompt + }) + if (openAITranscription?.text) { + return openAITranscription.text + } + break } - } else if (speechToTextConfig.name === 'assemblyAiTranscribe') { - const client = new AssemblyAI({ - apiKey: credentialData.assemblyAIApiKey - }) + case SpeechToTextType.ASSEMBLYAI_TRANSCRIBE: { + const assemblyAIClient = new AssemblyAI({ + apiKey: credentialData.assemblyAIApiKey + }) - const params = { - audio: audio_file, - speaker_labels: false - } + const params = { + audio: audio_file, + speaker_labels: false + } - const transcription = await client.transcripts.transcribe(params) - if (transcription?.text) { - return transcription.text + const assemblyAITranscription = await assemblyAIClient.transcripts.transcribe(params) + if (assemblyAITranscription?.text) { + return assemblyAITranscription.text + } + break + } + case SpeechToTextType.LOCALAI_STT: { + const LocalAIClientOptions: ClientOptions = { + apiKey: credentialData.localAIApiKey, + baseURL: speechToTextConfig?.baseUrl + } + const localAIClient = new OpenAIClient(LocalAIClientOptions) + const localAITranscription = await localAIClient.audio.transcriptions.create({ + file: new File([new Blob([audio_file])], upload.name), + model: speechToTextConfig?.model || 'whisper-1', + language: speechToTextConfig?.language, + temperature: speechToTextConfig?.temperature ? parseFloat(speechToTextConfig.temperature) : undefined, + prompt: speechToTextConfig?.prompt + }) + if (localAITranscription?.text) { + return localAITranscription.text + } + break } } } else { diff --git a/packages/components/src/storageUtils.ts b/packages/components/src/storageUtils.ts index 2b7a254f3bb..7bacec17651 100644 --- a/packages/components/src/storageUtils.ts +++ b/packages/components/src/storageUtils.ts @@ -4,12 +4,12 @@ import { DeleteObjectsCommand, GetObjectCommand, ListObjectsV2Command, PutObject import { Readable } from 'node:stream' import { getUserHome } from './utils' -export const addBase64FilesToStorage = async (file: string, chatflowid: string, fileNames: string[]) => { +export const addBase64FilesToStorage = async (fileBase64: string, chatflowid: string, fileNames: string[]) => { const storageType = getStorageType() if (storageType === 's3') { const { s3Client, Bucket } = getS3Config() - const splitDataURI = file.split(',') + const splitDataURI = fileBase64.split(',') const filename = splitDataURI.pop()?.split(':')[1] ?? '' const bf = Buffer.from(splitDataURI.pop() || '', 'base64') const mime = splitDataURI[0].split(':')[1].split(';')[0] @@ -32,7 +32,7 @@ export const addBase64FilesToStorage = async (file: string, chatflowid: string, fs.mkdirSync(dir, { recursive: true }) } - const splitDataURI = file.split(',') + const splitDataURI = fileBase64.split(',') const filename = splitDataURI.pop()?.split(':')[1] ?? '' const bf = Buffer.from(splitDataURI.pop() || '', 'base64') @@ -43,7 +43,40 @@ export const addBase64FilesToStorage = async (file: string, chatflowid: string, } } -export const addFileToStorage = async (mime: string, bf: Buffer, fileName: string, ...paths: string[]) => { +export const addArrayFilesToStorage = async (mime: string, bf: Buffer, fileName: string, fileNames: string[], ...paths: string[]) => { + const storageType = getStorageType() + if (storageType === 's3') { + const { s3Client, Bucket } = getS3Config() + + let Key = paths.reduce((acc, cur) => acc + '/' + cur, '') + '/' + fileName + if (Key.startsWith('/')) { + Key = Key.substring(1) + } + + const putObjCmd = new PutObjectCommand({ + Bucket, + Key, + ContentEncoding: 'base64', // required for binary data + ContentType: mime, + Body: bf + }) + await s3Client.send(putObjCmd) + fileNames.push(fileName) + return 'FILE-STORAGE::' + JSON.stringify(fileNames) + } else { + const dir = path.join(getStoragePath(), ...paths) + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }) + } + + const filePath = path.join(dir, fileName) + fs.writeFileSync(filePath, bf) + fileNames.push(fileName) + return 'FILE-STORAGE::' + JSON.stringify(fileNames) + } +} + +export const addSingleFileToStorage = async (mime: string, bf: Buffer, fileName: string, ...paths: string[]) => { const storageType = getStorageType() if (storageType === 's3') { const { s3Client, Bucket } = getS3Config() @@ -273,7 +306,7 @@ export const streamStorageFile = async ( } } -const getS3Config = () => { +export const getS3Config = () => { const accessKeyId = process.env.S3_STORAGE_ACCESS_KEY_ID const secretAccessKey = process.env.S3_STORAGE_SECRET_ACCESS_KEY const region = process.env.S3_STORAGE_REGION diff --git a/packages/server/marketplaces/agentflows/Customer Support Team Agents.json b/packages/server/marketplaces/agentflows/Customer Support Team Agents.json new file mode 100644 index 00000000000..1fe896d5927 --- /dev/null +++ b/packages/server/marketplaces/agentflows/Customer Support Team Agents.json @@ -0,0 +1,975 @@ +{ + "description": "Customer support team consisting of Support Representative and Quality Assurance Specialist to handle support tickets", + "nodes": [ + { + "id": "supervisor_0", + "position": { + "x": 343.59847938459717, + "y": 124.00657409829381 + }, + "type": "customNode", + "data": { + "id": "supervisor_0", + "label": "Supervisor", + "version": 1, + "name": "supervisor", + "type": "Supervisor", + "baseClasses": ["Supervisor"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Supervisor Name", + "name": "supervisorName", + "type": "string", + "placeholder": "Supervisor", + "default": "Supervisor", + "id": "supervisor_0-input-supervisorName-string" + }, + { + "label": "Supervisor Prompt", + "name": "supervisorPrompt", + "type": "string", + "description": "Prompt must contains {team_members}", + "rows": 4, + "default": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "additionalParams": true, + "id": "supervisor_0-input-supervisorPrompt-string" + }, + { + "label": "Recursion Limit", + "name": "recursionLimit", + "type": "number", + "description": "Maximum number of times a call can recurse. If not provided, defaults to 100.", + "default": 100, + "additionalParams": true, + "id": "supervisor_0-input-recursionLimit-number" + } + ], + "inputAnchors": [ + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, GroqChat. Best result with GPT-4 model", + "id": "supervisor_0-input-model-BaseChatModel" + }, + { + "label": "Input Moderation", + "description": "Detect text that could generate harmful output and prevent it from being sent to the language model", + "name": "inputModeration", + "type": "Moderation", + "optional": true, + "list": true, + "id": "supervisor_0-input-inputModeration-Moderation" + } + ], + "inputs": { + "supervisorName": "Supervisor", + "supervisorPrompt": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "model": "{{chatOpenAI_0.data.instance}}", + "recursionLimit": 100, + "inputModeration": "" + }, + "outputAnchors": [ + { + "id": "supervisor_0-output-supervisor-Supervisor", + "name": "supervisor", + "label": "Supervisor", + "description": "", + "type": "Supervisor" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 431, + "selected": false, + "positionAbsolute": { + "x": 343.59847938459717, + "y": 124.00657409829381 + }, + "dragging": false + }, + { + "id": "worker_0", + "position": { + "x": 848.0791314419789, + "y": 550.1251435439353 + }, + "type": "customNode", + "data": { + "id": "worker_0", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_0-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_0-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_0-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_0-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_0-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_0-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_0-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Quality Assurance Specialist", + "workerPrompt": "You are working at {company} and are now collaborating with your team on a customer request. Your task is to ensure that the support representative delivers the best possible support. It's crucial that the representative provides complete, accurate answers without making any assumptions.\n\nYour objective is to maintain top-tier support quality assurance within your team.\n\nReview the response drafted by the support representative for the customer's inquiry. Make sure the answer is thorough, accurate, and meets the high standards expected in customer support. Confirm that every aspect of the customer's question is addressed comprehensively, with a friendly and helpful tone. Verify that all references and sources used to find the information are included, ensuring the response is well-supported and leaves no questions unanswered.\n\nOnce your review is complete, return it to the Support Representative for finalization.", + "tools": "", + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_0-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "positionAbsolute": { + "x": 848.0791314419789, + "y": 550.1251435439353 + }, + "selected": false, + "dragging": false + }, + { + "id": "worker_1", + "position": { + "x": 1573.2919579833303, + "y": -234.22598124451474 + }, + "type": "customNode", + "data": { + "id": "worker_1", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_1-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_1-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_1-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_1-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_1-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_1-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_1-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Support Representative", + "workerPrompt": "As a representative at {company}, your role is to deliver exceptional customer support. Your objective is to provide the highest quality assistance, ensuring that your answers are comprehensive and based on facts without any assumptions.\n\nYour goal is to strive to be the most friendly and helpful support representative on your team.\n\nHere is your previous conversation with the customer:\n{conversation}\n\nCraft a detailed and informative response to the customer's inquiry, addressing all aspects of their question. Your response should include references to all sources used to find the answer, including external data or solutions. Ensure your answer is thorough, leaving no questions unanswered, while maintaining a friendly and supportive tone throughout.\n\nAlways use the tool provided - search_docs to look for answers. Check if you need to pass the result to Quality Assurance Specialist for review.", + "tools": ["{{retrieverTool_0.data.instance}}"], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"conversation\":\"{{customFunction_0.data.instance}}\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_1-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "positionAbsolute": { + "x": 1573.2919579833303, + "y": -234.22598124451474 + }, + "selected": false, + "dragging": false + }, + { + "id": "retrieverTool_0", + "position": { + "x": 1136.3773214513722, + "y": -661.7020929797668 + }, + "type": "customNode", + "data": { + "id": "retrieverTool_0", + "label": "Retriever Tool", + "version": 2, + "name": "retrieverTool", + "type": "RetrieverTool", + "baseClasses": ["RetrieverTool", "DynamicTool", "Tool", "StructuredTool", "Runnable"], + "category": "Tools", + "description": "Use a retriever as allowed tool for agent", + "inputParams": [ + { + "label": "Retriever Name", + "name": "name", + "type": "string", + "placeholder": "search_state_of_union", + "id": "retrieverTool_0-input-name-string" + }, + { + "label": "Retriever Description", + "name": "description", + "type": "string", + "description": "When should agent uses to retrieve documents", + "rows": 3, + "placeholder": "Searches and returns documents regarding the state-of-the-union.", + "id": "retrieverTool_0-input-description-string" + }, + { + "label": "Return Source Documents", + "name": "returnSourceDocuments", + "type": "boolean", + "optional": true, + "id": "retrieverTool_0-input-returnSourceDocuments-boolean" + } + ], + "inputAnchors": [ + { + "label": "Retriever", + "name": "retriever", + "type": "BaseRetriever", + "id": "retrieverTool_0-input-retriever-BaseRetriever" + } + ], + "inputs": { + "name": "search_docs", + "description": "Search and return documents about any issue or bugfix. Always give priority to this tool", + "retriever": "{{pinecone_0.data.instance}}", + "returnSourceDocuments": "" + }, + "outputAnchors": [ + { + "id": "retrieverTool_0-output-retrieverTool-RetrieverTool|DynamicTool|Tool|StructuredTool|Runnable", + "name": "retrieverTool", + "label": "RetrieverTool", + "description": "Use a retriever as allowed tool for agent", + "type": "RetrieverTool | DynamicTool | Tool | StructuredTool | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 602, + "selected": false, + "positionAbsolute": { + "x": 1136.3773214513722, + "y": -661.7020929797668 + }, + "dragging": false + }, + { + "id": "pinecone_0", + "position": { + "x": 767.1744633865214, + "y": -634.6870559540365 + }, + "type": "customNode", + "data": { + "id": "pinecone_0", + "label": "Pinecone", + "version": 3, + "name": "pinecone", + "type": "Pinecone", + "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], + "category": "Vector Stores", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["pineconeApi"], + "id": "pinecone_0-input-credential-credential" + }, + { + "label": "Pinecone Index", + "name": "pineconeIndex", + "type": "string", + "id": "pinecone_0-input-pineconeIndex-string" + }, + { + "label": "Pinecone Namespace", + "name": "pineconeNamespace", + "type": "string", + "placeholder": "my-first-namespace", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-pineconeNamespace-string" + }, + { + "label": "Pinecone Metadata Filter", + "name": "pineconeMetadataFilter", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "pinecone_0-input-pineconeMetadataFilter-json" + }, + { + "label": "Top K", + "name": "topK", + "description": "Number of top results to fetch. Default to 4", + "placeholder": "4", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" + } + ], + "inputAnchors": [ + { + "label": "Document", + "name": "document", + "type": "Document", + "list": true, + "optional": true, + "id": "pinecone_0-input-document-Document" + }, + { + "label": "Embeddings", + "name": "embeddings", + "type": "Embeddings", + "id": "pinecone_0-input-embeddings-Embeddings" + }, + { + "label": "Record Manager", + "name": "recordManager", + "type": "RecordManager", + "description": "Keep track of the record to prevent duplication", + "optional": true, + "id": "pinecone_0-input-recordManager-RecordManager" + } + ], + "inputs": { + "document": "", + "embeddings": "{{openAIEmbeddings_0.data.instance}}", + "recordManager": "", + "pineconeIndex": "flowiseindex", + "pineconeNamespace": "pinecone-flowise-docs", + "pineconeMetadataFilter": "", + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "description": "", + "options": [ + { + "id": "pinecone_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever", + "name": "retriever", + "label": "Pinecone Retriever", + "description": "", + "type": "Pinecone | VectorStoreRetriever | BaseRetriever" + }, + { + "id": "pinecone_0-output-vectorStore-Pinecone|VectorStore", + "name": "vectorStore", + "label": "Pinecone Vector Store", + "description": "", + "type": "Pinecone | VectorStore" + } + ], + "default": "retriever" + } + ], + "outputs": { + "output": "retriever" + }, + "selected": false + }, + "width": 300, + "height": 604, + "selected": false, + "positionAbsolute": { + "x": 767.1744633865214, + "y": -634.6870559540365 + }, + "dragging": false + }, + { + "id": "openAIEmbeddings_0", + "position": { + "x": 373.4730229546882, + "y": -480.5312248256105 + }, + "type": "customNode", + "data": { + "id": "openAIEmbeddings_0", + "label": "OpenAI Embeddings", + "version": 4, + "name": "openAIEmbeddings", + "type": "OpenAIEmbeddings", + "baseClasses": ["OpenAIEmbeddings", "Embeddings"], + "category": "Embeddings", + "description": "OpenAI API to generate embeddings for a given text", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "openAIEmbeddings_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "asyncOptions", + "loadMethod": "listModels", + "default": "text-embedding-ada-002", + "id": "openAIEmbeddings_0-input-modelName-asyncOptions" + }, + { + "label": "Strip New Lines", + "name": "stripNewLines", + "type": "boolean", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-stripNewLines-boolean" + }, + { + "label": "Batch Size", + "name": "batchSize", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-batchSize-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-basepath-string" + }, + { + "label": "Dimensions", + "name": "dimensions", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-dimensions-number" + } + ], + "inputAnchors": [], + "inputs": { + "modelName": "text-embedding-ada-002", + "stripNewLines": "", + "batchSize": "", + "timeout": "", + "basepath": "", + "dimensions": "" + }, + "outputAnchors": [ + { + "id": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings", + "name": "openAIEmbeddings", + "label": "OpenAIEmbeddings", + "description": "OpenAI API to generate embeddings for a given text", + "type": "OpenAIEmbeddings | Embeddings" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 423, + "selected": false, + "positionAbsolute": { + "x": 373.4730229546882, + "y": -480.5312248256105 + }, + "dragging": false + }, + { + "id": "customFunction_0", + "position": { + "x": 1214.8704502141265, + "y": 109.13589410824264 + }, + "type": "customNode", + "data": { + "id": "customFunction_0", + "label": "Custom JS Function", + "version": 1, + "name": "customFunction", + "type": "CustomFunction", + "baseClasses": ["CustomFunction", "Utilities"], + "category": "Utilities", + "description": "Execute custom javascript function", + "inputParams": [ + { + "label": "Input Variables", + "name": "functionInputVariables", + "description": "Input variables can be used in the function with prefix $. For example: $var", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "customFunction_0-input-functionInputVariables-json" + }, + { + "label": "Function Name", + "name": "functionName", + "type": "string", + "optional": true, + "placeholder": "My Function", + "id": "customFunction_0-input-functionName-string" + }, + { + "label": "Javascript Function", + "name": "javascriptFunction", + "type": "code", + "id": "customFunction_0-input-javascriptFunction-code" + } + ], + "inputAnchors": [], + "inputs": { + "functionInputVariables": "", + "functionName": "", + "javascriptFunction": "// Simulating fetching conversation between system and customer\nconst conversations =[\n {\n \"role\": \"bot\",\n \"content\": \"Hey how can I help you?\",\n },\n {\n \"role\": \"user\",\n \"content\": \"There is a bug when installing Flowise\",\n },\n {\n \"role\": \"bot\",\n \"content\": \"Can you tell me what was the error?\",\n }\n];\n\nreturn conversations;" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "description": "", + "options": [ + { + "id": "customFunction_0-output-output-string|number|boolean|json|array", + "name": "output", + "label": "Output", + "description": "", + "type": "string | number | boolean | json | array" + }, + { + "id": "customFunction_0-output-EndingNode-CustomFunction", + "name": "EndingNode", + "label": "Ending Node", + "description": "", + "type": "CustomFunction" + } + ], + "default": "output" + } + ], + "outputs": { + "output": "output" + }, + "selected": false + }, + "width": 300, + "height": 669, + "selected": false, + "positionAbsolute": { + "x": 1214.8704502141265, + "y": 109.13589410824264 + }, + "dragging": false + }, + { + "id": "chatOpenAI_0", + "position": { + "x": -29.209923556934555, + "y": -53.48197675171315 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 6, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "asyncOptions", + "loadMethod": "listModels", + "default": "gpt-3.5-turbo", + "id": "chatOpenAI_0-input-modelName-asyncOptions" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string" + }, + { + "label": "BaseOptions", + "name": "baseOptions", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-baseOptions-json" + }, + { + "label": "Allow Image Uploads", + "name": "allowImageUploads", + "type": "boolean", + "description": "Automatically uses gpt-4-vision-preview when image is being uploaded from chat. Only works with LLMChain, Conversation Chain, ReAct Agent, and Conversational Agent", + "default": false, + "optional": true, + "id": "chatOpenAI_0-input-allowImageUploads-boolean" + }, + { + "label": "Image Resolution", + "description": "This parameter controls the resolution in which the model views the image.", + "name": "imageResolution", + "type": "options", + "options": [ + { + "label": "Low", + "name": "low" + }, + { + "label": "High", + "name": "high" + }, + { + "label": "Auto", + "name": "auto" + } + ], + "default": "low", + "optional": false, + "additionalParams": true, + "id": "chatOpenAI_0-input-imageResolution-options" + } + ], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], + "inputs": { + "cache": "", + "modelName": "gpt-4o", + "temperature": "0", + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "", + "baseOptions": "", + "allowImageUploads": "", + "imageResolution": "low" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 669, + "selected": false, + "positionAbsolute": { + "x": -29.209923556934555, + "y": -53.48197675171315 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "openAIEmbeddings_0", + "sourceHandle": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings", + "target": "pinecone_0", + "targetHandle": "pinecone_0-input-embeddings-Embeddings", + "type": "buttonedge", + "id": "openAIEmbeddings_0-openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings-pinecone_0-pinecone_0-input-embeddings-Embeddings" + }, + { + "source": "pinecone_0", + "sourceHandle": "pinecone_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever", + "target": "retrieverTool_0", + "targetHandle": "retrieverTool_0-input-retriever-BaseRetriever", + "type": "buttonedge", + "id": "pinecone_0-pinecone_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever-retrieverTool_0-retrieverTool_0-input-retriever-BaseRetriever" + }, + { + "source": "retrieverTool_0", + "sourceHandle": "retrieverTool_0-output-retrieverTool-RetrieverTool|DynamicTool|Tool|StructuredTool|Runnable", + "target": "worker_1", + "targetHandle": "worker_1-input-tools-Tool", + "type": "buttonedge", + "id": "retrieverTool_0-retrieverTool_0-output-retrieverTool-RetrieverTool|DynamicTool|Tool|StructuredTool|Runnable-worker_1-worker_1-input-tools-Tool" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_1", + "targetHandle": "worker_1-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_1-worker_1-input-supervisor-Supervisor" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_0", + "targetHandle": "worker_0-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_0-worker_0-input-supervisor-Supervisor" + }, + { + "source": "customFunction_0", + "sourceHandle": "customFunction_0-output-output-string|number|boolean|json|array", + "target": "worker_1", + "targetHandle": "worker_1-input-promptValues-json", + "type": "buttonedge", + "id": "customFunction_0-customFunction_0-output-output-string|number|boolean|json|array-worker_1-worker_1-input-promptValues-json" + }, + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "supervisor_0", + "targetHandle": "supervisor_0-input-model-BaseChatModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-supervisor_0-supervisor_0-input-model-BaseChatModel" + } + ] +} diff --git a/packages/server/marketplaces/agentflows/Lead Outreach.json b/packages/server/marketplaces/agentflows/Lead Outreach.json new file mode 100644 index 00000000000..0152e9d58cf --- /dev/null +++ b/packages/server/marketplaces/agentflows/Lead Outreach.json @@ -0,0 +1,560 @@ +{ + "description": "Research leads and create personalized email drafts for sales team", + "nodes": [ + { + "id": "supervisor_0", + "position": { + "x": 528, + "y": 241 + }, + "type": "customNode", + "data": { + "id": "supervisor_0", + "label": "Supervisor", + "version": 1, + "name": "supervisor", + "type": "Supervisor", + "baseClasses": ["Supervisor"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Supervisor Name", + "name": "supervisorName", + "type": "string", + "placeholder": "Supervisor", + "default": "Supervisor", + "id": "supervisor_0-input-supervisorName-string" + }, + { + "label": "Supervisor Prompt", + "name": "supervisorPrompt", + "type": "string", + "description": "Prompt must contains {team_members}", + "rows": 4, + "default": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "additionalParams": true, + "id": "supervisor_0-input-supervisorPrompt-string" + }, + { + "label": "Recursion Limit", + "name": "recursionLimit", + "type": "number", + "description": "Maximum number of times a call can recurse. If not provided, defaults to 100.", + "default": 100, + "additionalParams": true, + "id": "supervisor_0-input-recursionLimit-number" + } + ], + "inputAnchors": [ + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, GroqChat. Best result with GPT-4 model", + "id": "supervisor_0-input-model-BaseChatModel" + }, + { + "label": "Input Moderation", + "description": "Detect text that could generate harmful output and prevent it from being sent to the language model", + "name": "inputModeration", + "type": "Moderation", + "optional": true, + "list": true, + "id": "supervisor_0-input-inputModeration-Moderation" + } + ], + "inputs": { + "supervisorName": "Supervisor", + "supervisorPrompt": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "model": "{{chatOpenAI_0.data.instance}}", + "recursionLimit": 100, + "inputModeration": "" + }, + "outputAnchors": [ + { + "id": "supervisor_0-output-supervisor-Supervisor", + "name": "supervisor", + "label": "Supervisor", + "description": "", + "type": "Supervisor" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 431, + "positionAbsolute": { + "x": 528, + "y": 241 + }, + "selected": false + }, + { + "id": "chatOpenAI_0", + "position": { + "x": 141.20413030236358, + "y": 37.29175117907283 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 6, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "asyncOptions", + "loadMethod": "listModels", + "default": "gpt-3.5-turbo", + "id": "chatOpenAI_0-input-modelName-asyncOptions" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string" + }, + { + "label": "BaseOptions", + "name": "baseOptions", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-baseOptions-json" + }, + { + "label": "Allow Image Uploads", + "name": "allowImageUploads", + "type": "boolean", + "description": "Automatically uses gpt-4-vision-preview when image is being uploaded from chat. Only works with LLMChain, Conversation Chain, ReAct Agent, and Conversational Agent", + "default": false, + "optional": true, + "id": "chatOpenAI_0-input-allowImageUploads-boolean" + }, + { + "label": "Image Resolution", + "description": "This parameter controls the resolution in which the model views the image.", + "name": "imageResolution", + "type": "options", + "options": [ + { + "label": "Low", + "name": "low" + }, + { + "label": "High", + "name": "high" + }, + { + "label": "Auto", + "name": "auto" + } + ], + "default": "low", + "optional": false, + "additionalParams": true, + "id": "chatOpenAI_0-input-imageResolution-options" + } + ], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], + "inputs": { + "cache": "", + "modelName": "gpt-4o", + "temperature": 0.9, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "", + "baseOptions": "", + "allowImageUploads": "", + "imageResolution": "low" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 669, + "selected": false, + "positionAbsolute": { + "x": 141.20413030236358, + "y": 37.29175117907283 + }, + "dragging": false + }, + { + "id": "worker_0", + "position": { + "x": 918.2245199532538, + "y": 112.34294138561228 + }, + "type": "customNode", + "data": { + "id": "worker_0", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_0-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_0-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_0-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_0-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_0-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_0-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_0-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Lead Research", + "workerPrompt": "As a member of the sales team at {company}, your mission is to explore the digital landscape for potential leads. Equipped with advanced tools and a strategic approach, you analyze data, trends, and interactions to discover opportunities that others might miss. Your efforts are vital in creating pathways for meaningful engagements and driving the company's growth.\n\nYour goal is to identify high-value leads that align with our ideal customer profile.\n\nPerform a thorough analysis of {lead_company}, a company that has recently shown interest in our solutions. Use all available data sources to create a detailed profile, concentrating on key decision-makers, recent business developments, and potential needs that match our offerings. This task is essential for effectively customizing our engagement strategy.\n\nAvoid making assumptions and only use information you are certain about.\n\nYou should produce a comprehensive report on {lead_person}, including company background, key personnel, recent milestones, and identified needs. Emphasize potential areas where our solutions can add value and suggest tailored engagement strategies. Pass the info to Lead Sales Representative.", + "tools": ["{{googleCustomSearch_0.data.instance}}"], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"lead_company\":\"Langchain\",\"lead_person\":\"Harrison Chase\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_0-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 918.2245199532538, + "y": 112.34294138561228 + }, + "dragging": false + }, + { + "id": "worker_1", + "position": { + "x": 1318.2245199532538, + "y": 112.34294138561228 + }, + "type": "customNode", + "data": { + "id": "worker_1", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_1-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_1-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_1-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_1-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_1-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_1-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_1-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Lead Sales Representative", + "workerPrompt": "You play a crucial role within {company} as the link between potential clients and the solutions they need. By crafting engaging, personalized messages, you not only inform leads about our company offerings but also make them feel valued and understood. Your role is essential in transforming interest into action, guiding leads from initial curiosity to committed engagement.\n\nYour goal is to nurture leads with tailored, compelling communications.\n\nLeveraging the insights from the lead profiling report on {lead_company}, create a personalized outreach campaign targeting {lead_person}, the {position} of {lead_company}. he campaign should highlight their recent {lead_activity} and demonstrate how our solutions can support their objectives. Your communication should align with {lead_company}'s company culture and values, showcasing a thorough understanding of their business and needs. Avoid making assumptions and use only verified information.\n\nThe output should be a series of personalized email drafts customized for {lead_company}, specifically addressing {lead_person}. Each draft should present a compelling narrative that connects our solutions to their recent accomplishments and future goals. Ensure the tone is engaging, professional, and consistent with {lead_company}'s corporate identity. Keep in natural, don't use strange and fancy words.", + "tools": "", + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"lead_company\":\"Langchain\",\"lead_person\":\"Harrison Chase\",\"position\":\"CEO\",\"lead_activity\":\"Langgraph launch\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_1-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 1318.2245199532538, + "y": 112.34294138561228 + }, + "dragging": false + }, + { + "id": "googleCustomSearch_0", + "position": { + "x": 542.5920618578143, + "y": -102.36639408227376 + }, + "type": "customNode", + "data": { + "id": "googleCustomSearch_0", + "label": "Google Custom Search", + "version": 1, + "name": "googleCustomSearch", + "type": "GoogleCustomSearchAPI", + "baseClasses": ["GoogleCustomSearchAPI", "Tool", "StructuredTool", "Runnable"], + "category": "Tools", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["googleCustomSearchApi"], + "id": "googleCustomSearch_0-input-credential-credential" + } + ], + "inputAnchors": [], + "inputs": {}, + "outputAnchors": [ + { + "id": "googleCustomSearch_0-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "name": "googleCustomSearch", + "label": "GoogleCustomSearchAPI", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "type": "GoogleCustomSearchAPI | Tool | StructuredTool | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 275, + "selected": false, + "positionAbsolute": { + "x": 542.5920618578143, + "y": -102.36639408227376 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_0", + "targetHandle": "worker_0-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_0-worker_0-input-supervisor-Supervisor" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_1", + "targetHandle": "worker_1-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_1-worker_1-input-supervisor-Supervisor" + }, + { + "source": "googleCustomSearch_0", + "sourceHandle": "googleCustomSearch_0-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "target": "worker_0", + "targetHandle": "worker_0-input-tools-Tool", + "type": "buttonedge", + "id": "googleCustomSearch_0-googleCustomSearch_0-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable-worker_0-worker_0-input-tools-Tool" + }, + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "supervisor_0", + "targetHandle": "supervisor_0-input-model-BaseChatModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-supervisor_0-supervisor_0-input-model-BaseChatModel" + } + ] +} diff --git a/packages/server/marketplaces/agentflows/Portfolio Management Team.json b/packages/server/marketplaces/agentflows/Portfolio Management Team.json new file mode 100644 index 00000000000..02e6b0810ad --- /dev/null +++ b/packages/server/marketplaces/agentflows/Portfolio Management Team.json @@ -0,0 +1,783 @@ +{ + "description": "A team of portfolio manager, financial analyst, and risk manager working together to optimize an investment portfolio.", + "nodes": [ + { + "id": "supervisor_0", + "position": { + "x": 242.0267719253082, + "y": 185.62152813526978 + }, + "type": "customNode", + "data": { + "id": "supervisor_0", + "label": "Supervisor", + "version": 1, + "name": "supervisor", + "type": "Supervisor", + "baseClasses": ["Supervisor"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Supervisor Name", + "name": "supervisorName", + "type": "string", + "placeholder": "Supervisor", + "default": "Supervisor", + "id": "supervisor_0-input-supervisorName-string" + }, + { + "label": "Supervisor Prompt", + "name": "supervisorPrompt", + "type": "string", + "description": "Prompt must contains {team_members}", + "rows": 4, + "default": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "additionalParams": true, + "id": "supervisor_0-input-supervisorPrompt-string" + }, + { + "label": "Recursion Limit", + "name": "recursionLimit", + "type": "number", + "description": "Maximum number of times a call can recurse. If not provided, defaults to 100.", + "default": 100, + "additionalParams": true, + "id": "supervisor_0-input-recursionLimit-number" + } + ], + "inputAnchors": [ + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, GroqChat. Best result with GPT-4 model", + "id": "supervisor_0-input-model-BaseChatModel" + }, + { + "label": "Input Moderation", + "description": "Detect text that could generate harmful output and prevent it from being sent to the language model", + "name": "inputModeration", + "type": "Moderation", + "optional": true, + "list": true, + "id": "supervisor_0-input-inputModeration-Moderation" + } + ], + "inputs": { + "supervisorName": "Supervisor", + "supervisorPrompt": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "model": "{{chatOpenAI_0.data.instance}}", + "recursionLimit": 100, + "inputModeration": "" + }, + "outputAnchors": [ + { + "id": "supervisor_0-output-supervisor-Supervisor", + "name": "supervisor", + "label": "Supervisor", + "description": "", + "type": "Supervisor" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 431, + "selected": false, + "positionAbsolute": { + "x": 242.0267719253082, + "y": 185.62152813526978 + }, + "dragging": false + }, + { + "id": "worker_0", + "position": { + "x": 637.3247841463353, + "y": 115.189653148269 + }, + "type": "customNode", + "data": { + "id": "worker_0", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_0-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_0-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_0-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_0-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_0-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_0-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_0-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Portfolio Manager", + "workerPrompt": "As the Portfolio Manager at {company}, you play a crucial role in overseeing and optimizing our investment portfolio. Your expertise in market analysis, strategic planning, and risk management is essential for making informed investment decisions that drive our financial growth.\n\nYour goal is to develop and implement effective investment strategies that align with our clients' financial goals and risk tolerance.\n\nAnalyze market trends, economic data, and financial reports to identify potential investment opportunities. Collaborate with the Financial Analyst and Risk Manager to ensure that your strategies are well-informed and balanced. Continuously monitor the portfolio's performance and make adjustments as necessary to maximize returns while managing risk.\n\nYour task is to create a comprehensive investment strategy for {portfolio_name}, taking into account the client's financial objectives and risk tolerance. Ensure that your strategy is backed by thorough market research and financial analysis, and includes a plan for regular performance reviews and adjustments.\n\nThe output should be a detailed investment strategy report for {portfolio_name}, including market analysis, recommended investments, risk management approaches, and performance monitoring plans. Ensure that the strategy is designed to achieve the client's financial goals while maintaining an appropriate risk level.", + "tools": ["{{googleCustomSearch_0.data.instance}}"], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"portfolio_name\":\"Tesla Inc\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_0-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 637.3247841463353, + "y": 115.189653148269 + }, + "dragging": false + }, + { + "id": "worker_1", + "position": { + "x": 1037.3247841463353, + "y": 115.189653148269 + }, + "type": "customNode", + "data": { + "id": "worker_1", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_1-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_1-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_1-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_1-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_1-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_1-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_1-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Financial Analyst", + "workerPrompt": "As a Financial Analyst at {company}, you are a vital member of our portfolio management team, providing in-depth research and analysis to support informed investment decisions. Your analytical skills and market insights are key to identifying profitable opportunities and enhancing the overall performance of our portfolio.\n\nYour goal is to conduct thorough financial analysis and market research to support the Portfolio Manager in developing effective investment strategies.\n\nAnalyze financial data, market trends, and economic indicators to identify potential investment opportunities. Prepare detailed reports and presentations that highlight your findings and recommendations. Collaborate closely with the Portfolio Manager and Risk Manager to ensure that your analyses contribute to well-informed and balanced investment strategies.\n\nYour task is to perform a comprehensive analysis of {investment_opportunity} for inclusion in {portfolio_name}. Use various financial metrics and market data to evaluate the potential risks and returns. Provide clear, actionable insights and recommendations based on your analysis.\n\nThe output should be a detailed financial analysis report for {investment_opportunity}, including key financial metrics, market trends, risk assessment, and your investment recommendation. Ensure that the report is well-supported by data and provides valuable insights to inform the Portfolio Manager's decision-making process.", + "tools": ["{{googleCustomSearch_1.data.instance}}"], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"investment_opportunity\":\"Tech Summit Fund\",\"portfolio_name\":\"Tesla Inc\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_1-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 1037.3247841463353, + "y": 115.189653148269 + }, + "dragging": false + }, + { + "id": "worker_2", + "position": { + "x": 1482.836195011232, + "y": 119.54481208270889 + }, + "type": "customNode", + "data": { + "id": "worker_2", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_2-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_2-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_2-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_2-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_2-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_2-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_2-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Risk Manager", + "workerPrompt": "As the Risk Manager at {company}, you play a pivotal role in ensuring the stability and resilience of our investment portfolio. Your expertise in risk assessment and mitigation is essential for maintaining an appropriate balance between risk and return, aligning with our clients' risk tolerance and financial goals.\n\nYour goal is to identify, assess, and mitigate risks associated with the investment portfolio to safeguard its performance and align with our clients' risk tolerance.\n\nEvaluate potential risks for current and prospective investments using quantitative and qualitative analysis. Collaborate with the Portfolio Manager and Financial Analyst to integrate risk management strategies into the overall investment approach. Continuously monitor the portfolio to identify emerging risks and implement measures to mitigate them.\n\nYour task is to perform a comprehensive risk assessment for {portfolio_name}, focusing on potential market, credit, and operational risks. Develop and recommend risk mitigation strategies that align with the client's risk tolerance and investment objectives.\n\nThe output should be a detailed risk assessment report for {portfolio_name}, including identification of key risks, risk metrics, and recommended mitigation strategies. Ensure that the report provides actionable insights and supports the Portfolio Manager in maintaining a balanced and resilient portfolio.", + "tools": ["{{googleCustomSearch_2.data.instance}}"], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"portfolio_name\":\"Tesla Inc\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_2-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 1482.836195011232, + "y": 119.54481208270889 + }, + "dragging": false + }, + { + "id": "chatOpenAI_0", + "position": { + "x": -120.80560304817006, + "y": 71.63806380387018 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 6, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "asyncOptions", + "loadMethod": "listModels", + "default": "gpt-3.5-turbo", + "id": "chatOpenAI_0-input-modelName-asyncOptions" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string" + }, + { + "label": "BaseOptions", + "name": "baseOptions", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-baseOptions-json" + }, + { + "label": "Allow Image Uploads", + "name": "allowImageUploads", + "type": "boolean", + "description": "Automatically uses gpt-4-vision-preview when image is being uploaded from chat. Only works with LLMChain, Conversation Chain, ReAct Agent, and Conversational Agent", + "default": false, + "optional": true, + "id": "chatOpenAI_0-input-allowImageUploads-boolean" + }, + { + "label": "Image Resolution", + "description": "This parameter controls the resolution in which the model views the image.", + "name": "imageResolution", + "type": "options", + "options": [ + { + "label": "Low", + "name": "low" + }, + { + "label": "High", + "name": "high" + }, + { + "label": "Auto", + "name": "auto" + } + ], + "default": "low", + "optional": false, + "additionalParams": true, + "id": "chatOpenAI_0-input-imageResolution-options" + } + ], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], + "inputs": { + "cache": "", + "modelName": "gpt-4o", + "temperature": "0", + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "", + "baseOptions": "", + "allowImageUploads": "", + "imageResolution": "low" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 669, + "selected": false, + "positionAbsolute": { + "x": -120.80560304817006, + "y": 71.63806380387018 + }, + "dragging": false + }, + { + "id": "googleCustomSearch_0", + "position": { + "x": 268.39206549032804, + "y": -209.224097209214 + }, + "type": "customNode", + "data": { + "id": "googleCustomSearch_0", + "label": "Google Custom Search", + "version": 1, + "name": "googleCustomSearch", + "type": "GoogleCustomSearchAPI", + "baseClasses": ["GoogleCustomSearchAPI", "Tool", "StructuredTool", "Runnable"], + "category": "Tools", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["googleCustomSearchApi"], + "id": "googleCustomSearch_0-input-credential-credential" + } + ], + "inputAnchors": [], + "inputs": {}, + "outputAnchors": [ + { + "id": "googleCustomSearch_0-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "name": "googleCustomSearch", + "label": "GoogleCustomSearchAPI", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "type": "GoogleCustomSearchAPI | Tool | StructuredTool | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 275, + "selected": false, + "positionAbsolute": { + "x": 268.39206549032804, + "y": -209.224097209214 + }, + "dragging": false + }, + { + "id": "googleCustomSearch_1", + "position": { + "x": 708.2007597123056, + "y": -214.21906914647434 + }, + "type": "customNode", + "data": { + "id": "googleCustomSearch_1", + "label": "Google Custom Search", + "version": 1, + "name": "googleCustomSearch", + "type": "GoogleCustomSearchAPI", + "baseClasses": ["GoogleCustomSearchAPI", "Tool", "StructuredTool", "Runnable"], + "category": "Tools", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["googleCustomSearchApi"], + "id": "googleCustomSearch_1-input-credential-credential" + } + ], + "inputAnchors": [], + "inputs": {}, + "outputAnchors": [ + { + "id": "googleCustomSearch_1-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "name": "googleCustomSearch", + "label": "GoogleCustomSearchAPI", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "type": "GoogleCustomSearchAPI | Tool | StructuredTool | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 275, + "selected": false, + "positionAbsolute": { + "x": 708.2007597123056, + "y": -214.21906914647434 + }, + "dragging": false + }, + { + "id": "googleCustomSearch_2", + "position": { + "x": 1148.6913242910439, + "y": -216.29397639610963 + }, + "type": "customNode", + "data": { + "id": "googleCustomSearch_2", + "label": "Google Custom Search", + "version": 1, + "name": "googleCustomSearch", + "type": "GoogleCustomSearchAPI", + "baseClasses": ["GoogleCustomSearchAPI", "Tool", "StructuredTool", "Runnable"], + "category": "Tools", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["googleCustomSearchApi"], + "id": "googleCustomSearch_2-input-credential-credential" + } + ], + "inputAnchors": [], + "inputs": {}, + "outputAnchors": [ + { + "id": "googleCustomSearch_2-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "name": "googleCustomSearch", + "label": "GoogleCustomSearchAPI", + "description": "Wrapper around Google Custom Search API - a real-time API to access Google search results", + "type": "GoogleCustomSearchAPI | Tool | StructuredTool | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 275, + "selected": false, + "positionAbsolute": { + "x": 1148.6913242910439, + "y": -216.29397639610963 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "googleCustomSearch_0", + "sourceHandle": "googleCustomSearch_0-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "target": "worker_0", + "targetHandle": "worker_0-input-tools-Tool", + "type": "buttonedge", + "id": "googleCustomSearch_0-googleCustomSearch_0-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable-worker_0-worker_0-input-tools-Tool" + }, + { + "source": "googleCustomSearch_1", + "sourceHandle": "googleCustomSearch_1-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "target": "worker_1", + "targetHandle": "worker_1-input-tools-Tool", + "type": "buttonedge", + "id": "googleCustomSearch_1-googleCustomSearch_1-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable-worker_1-worker_1-input-tools-Tool" + }, + { + "source": "googleCustomSearch_2", + "sourceHandle": "googleCustomSearch_2-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable", + "target": "worker_2", + "targetHandle": "worker_2-input-tools-Tool", + "type": "buttonedge", + "id": "googleCustomSearch_2-googleCustomSearch_2-output-googleCustomSearch-GoogleCustomSearchAPI|Tool|StructuredTool|Runnable-worker_2-worker_2-input-tools-Tool" + }, + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "supervisor_0", + "targetHandle": "supervisor_0-input-model-BaseChatModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-supervisor_0-supervisor_0-input-model-BaseChatModel" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_0", + "targetHandle": "worker_0-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_0-worker_0-input-supervisor-Supervisor" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_1", + "targetHandle": "worker_1-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_1-worker_1-input-supervisor-Supervisor" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_2", + "targetHandle": "worker_2-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_2-worker_2-input-supervisor-Supervisor" + } + ] +} diff --git a/packages/server/marketplaces/agentflows/Software Team.json b/packages/server/marketplaces/agentflows/Software Team.json new file mode 100644 index 00000000000..b55a4648917 --- /dev/null +++ b/packages/server/marketplaces/agentflows/Software Team.json @@ -0,0 +1,504 @@ +{ + "description": "Software engineering team working together to build a feature, solve a problem, or complete a task.", + "nodes": [ + { + "id": "supervisor_0", + "position": { + "x": 577, + "y": 156 + }, + "type": "customNode", + "data": { + "id": "supervisor_0", + "label": "Supervisor", + "version": 1, + "name": "supervisor", + "type": "Supervisor", + "baseClasses": ["Supervisor"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Supervisor Name", + "name": "supervisorName", + "type": "string", + "placeholder": "Supervisor", + "default": "Supervisor", + "id": "supervisor_0-input-supervisorName-string" + }, + { + "label": "Supervisor Prompt", + "name": "supervisorPrompt", + "type": "string", + "description": "Prompt must contains {team_members}", + "rows": 4, + "default": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "additionalParams": true, + "id": "supervisor_0-input-supervisorPrompt-string" + }, + { + "label": "Recursion Limit", + "name": "recursionLimit", + "type": "number", + "description": "Maximum number of times a call can recurse. If not provided, defaults to 100.", + "default": 100, + "additionalParams": true, + "id": "supervisor_0-input-recursionLimit-number" + } + ], + "inputAnchors": [ + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, GroqChat. Best result with GPT-4 model", + "id": "supervisor_0-input-model-BaseChatModel" + }, + { + "label": "Input Moderation", + "description": "Detect text that could generate harmful output and prevent it from being sent to the language model", + "name": "inputModeration", + "type": "Moderation", + "optional": true, + "list": true, + "id": "supervisor_0-input-inputModeration-Moderation" + } + ], + "inputs": { + "supervisorName": "Supervisor", + "supervisorPrompt": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "model": "{{chatOpenAI_0.data.instance}}", + "recursionLimit": 100, + "inputModeration": "" + }, + "outputAnchors": [ + { + "id": "supervisor_0-output-supervisor-Supervisor", + "name": "supervisor", + "label": "Supervisor", + "description": "", + "type": "Supervisor" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 431, + "positionAbsolute": { + "x": 577, + "y": 156 + }, + "selected": false + }, + { + "id": "worker_0", + "position": { + "x": 969.3717362716295, + "y": 77.52271438462338 + }, + "type": "customNode", + "data": { + "id": "worker_0", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_0-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_0-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_0-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_0-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_0-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_0-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_0-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Senior Software Engineer", + "workerPrompt": "As a Senior Software Engineer at {company}, you are a pivotal part of our innovative development team. Your expertise and leadership drive the creation of robust, scalable software solutions that meet the needs of our diverse clientele. By applying best practices in software development, you ensure that our products are reliable, efficient, and maintainable.\n\nYour goal is to lead the development of high-quality software solutions.\n\nUtilize your deep technical knowledge and experience to architect, design, and implement software systems that address complex problems. Collaborate closely with other engineers, reviewers to ensure that the solutions you develop align with business objectives and user needs.\n\nDesign and implement new feature for the given task, ensuring it integrates seamlessly with existing systems and meets performance requirements. Use your understanding of {technology} to build this feature. Make sure to adhere to our coding standards and follow best practices.\n\nThe output should be a fully functional, well-documented feature that enhances our product's capabilities. Include detailed comments in the code. Pass the code to Quality Assurance Engineer for review if neccessary. Once ther review is good enough, produce a finalized version of the code.", + "tools": "", + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"technology\":\"React, NodeJS, ExpressJS, Tailwindcss\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_0-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 969.3717362716295, + "y": 77.52271438462338 + }, + "dragging": false + }, + { + "id": "worker_1", + "position": { + "x": 1369.3717362716295, + "y": 77.52271438462338 + }, + "type": "customNode", + "data": { + "id": "worker_1", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_1-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_1-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_1-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_1-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_1-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_1-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_1-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "Code Reviewer", + "workerPrompt": "As a Quality Assurance Engineer at {company}, you are an integral part of our development team, ensuring that our software products are of the highest quality. Your meticulous attention to detail and expertise in testing methodologies are crucial in identifying defects and ensuring that our code meets the highest standards.\n\nYour goal is to ensure the delivery of high-quality software through thorough code review and testing.\n\nReview the codebase for the new feature designed and implemented by the Senior Software Engineer. Your expertise goes beyond mere code inspection; you are adept at ensuring that developments not only function as intended but also adhere to the team's coding standards, enhance maintainability, and seamlessly integrate with existing systems. \n\nWith a deep appreciation for collaborative development, you provide constructive feedback, guiding contributors towards best practices and fostering a culture of continuous improvement. Your meticulous approach to reviewing code, coupled with your ability to foresee potential issues and recommend proactive solutions, ensures the delivery of high-quality software that is robust, scalable, and aligned with the team's strategic goals.\n\nAlways pass back the review and feedback to Senior Software Engineer.", + "tools": "", + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_1-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 1369.3717362716295, + "y": 77.52271438462338 + }, + "dragging": false + }, + { + "id": "chatOpenAI_0", + "position": { + "x": 201.1230948105134, + "y": 70.78573663723421 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 6, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "asyncOptions", + "loadMethod": "listModels", + "default": "gpt-3.5-turbo", + "id": "chatOpenAI_0-input-modelName-asyncOptions" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string" + }, + { + "label": "BaseOptions", + "name": "baseOptions", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-baseOptions-json" + }, + { + "label": "Allow Image Uploads", + "name": "allowImageUploads", + "type": "boolean", + "description": "Automatically uses gpt-4-vision-preview when image is being uploaded from chat. Only works with LLMChain, Conversation Chain, ReAct Agent, and Conversational Agent", + "default": false, + "optional": true, + "id": "chatOpenAI_0-input-allowImageUploads-boolean" + }, + { + "label": "Image Resolution", + "description": "This parameter controls the resolution in which the model views the image.", + "name": "imageResolution", + "type": "options", + "options": [ + { + "label": "Low", + "name": "low" + }, + { + "label": "High", + "name": "high" + }, + { + "label": "Auto", + "name": "auto" + } + ], + "default": "low", + "optional": false, + "additionalParams": true, + "id": "chatOpenAI_0-input-imageResolution-options" + } + ], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], + "inputs": { + "cache": "", + "modelName": "gpt-4o", + "temperature": "0", + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "", + "baseOptions": "", + "allowImageUploads": "", + "imageResolution": "low" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 669, + "selected": false, + "positionAbsolute": { + "x": 201.1230948105134, + "y": 70.78573663723421 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "supervisor_0", + "targetHandle": "supervisor_0-input-model-BaseChatModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-supervisor_0-supervisor_0-input-model-BaseChatModel" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_1", + "targetHandle": "worker_1-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_1-worker_1-input-supervisor-Supervisor" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_0", + "targetHandle": "worker_0-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_0-worker_0-input-supervisor-Supervisor" + } + ] +} diff --git a/packages/server/marketplaces/agentflows/Text to SQL.json b/packages/server/marketplaces/agentflows/Text to SQL.json new file mode 100644 index 00000000000..2e3f6522206 --- /dev/null +++ b/packages/server/marketplaces/agentflows/Text to SQL.json @@ -0,0 +1,768 @@ +{ + "description": "Text to SQL query process using team of 3 agents: SQL Expert, SQL Reviewer, and SQL Executor", + "nodes": [ + { + "id": "supervisor_0", + "position": { + "x": -275.4818449163403, + "y": 462.4424369159454 + }, + "type": "customNode", + "data": { + "id": "supervisor_0", + "label": "Supervisor", + "version": 1, + "name": "supervisor", + "type": "Supervisor", + "baseClasses": ["Supervisor"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Supervisor Name", + "name": "supervisorName", + "type": "string", + "placeholder": "Supervisor", + "default": "Supervisor", + "id": "supervisor_0-input-supervisorName-string" + }, + { + "label": "Supervisor Prompt", + "name": "supervisorPrompt", + "type": "string", + "description": "Prompt must contains {team_members}", + "rows": 4, + "default": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "additionalParams": true, + "id": "supervisor_0-input-supervisorPrompt-string" + }, + { + "label": "Recursion Limit", + "name": "recursionLimit", + "type": "number", + "description": "Maximum number of times a call can recurse. If not provided, defaults to 100.", + "default": 100, + "additionalParams": true, + "id": "supervisor_0-input-recursionLimit-number" + } + ], + "inputAnchors": [ + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, GroqChat. Best result with GPT-4 model", + "id": "supervisor_0-input-model-BaseChatModel" + }, + { + "label": "Input Moderation", + "description": "Detect text that could generate harmful output and prevent it from being sent to the language model", + "name": "inputModeration", + "type": "Moderation", + "optional": true, + "list": true, + "id": "supervisor_0-input-inputModeration-Moderation" + } + ], + "inputs": { + "supervisorName": "Supervisor", + "supervisorPrompt": "You are a supervisor tasked with managing a conversation between the following workers: {team_members}.\nGiven the following user request, respond with the worker to act next.\nEach worker will perform a task and respond with their results and status.\nWhen finished, respond with FINISH.\nSelect strategically to minimize the number of steps taken.", + "model": "{{chatOpenAI_0.data.instance}}", + "recursionLimit": 100, + "inputModeration": "" + }, + "outputAnchors": [ + { + "id": "supervisor_0-output-supervisor-Supervisor", + "name": "supervisor", + "label": "Supervisor", + "description": "", + "type": "Supervisor" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 431, + "selected": false, + "positionAbsolute": { + "x": -275.4818449163403, + "y": 462.4424369159454 + }, + "dragging": false + }, + { + "id": "worker_0", + "position": { + "x": 483.6310212673076, + "y": 304.6138109554939 + }, + "type": "customNode", + "data": { + "id": "worker_0", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_0-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_0-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_0-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_0-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_0-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_0-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_0-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "SQL Expert", + "workerPrompt": "As an SQL Expert at {company}, you are a critical member of our data team, responsible for designing, optimizing, and maintaining our database systems. Your expertise in SQL and database management ensures that our data is accurate, accessible, and efficiently processed.\n\nYour goal is to develop and optimize complex SQL queries to answer the question.\n\nYou are given the following schema:\n{schema}\n\nYour task is to use the provided schema, and produce the SQL query needed to answer user question. Collaborate with SQL Reviewer and SQL Executor for feedback and review, ensuring that your SQL solutions is correct and follow best practices in database design and query optimization to enhance performance and reliability.\n\nThe output should be a an optimized SQL query. Ensure that your output only contains SQL query, nothing else. Remember, only output SQL query.", + "tools": [], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\",\"schema\":\"{{customFunction_0.data.instance}}\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_0-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 483.6310212673076, + "y": 304.6138109554939 + }, + "dragging": false + }, + { + "id": "worker_1", + "position": { + "x": 1214.157684503848, + "y": 248.8294849061827 + }, + "type": "customNode", + "data": { + "id": "worker_1", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_1-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_1-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_1-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_1-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_1-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_1-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_1-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "SQL Executor", + "workerPrompt": "As an SQL Executor at {company}, you must ensure the SQL query can be executed with no error.\n\nYou must use the execute_sql tool to execute the SQL query provided by SQL Expert and get the result. Verify the result is indeed correct and error-free. Collaborate with the SQL Expert and SQL Reviewer to make sure the SQL query is valid and successfully fetches back the right information.\n\nREMEMBER, always use the execute_sql tool!", + "tools": ["{{customTool_0.data.instance}}"], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_1-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 1214.157684503848, + "y": 248.8294849061827 + }, + "dragging": false + }, + { + "id": "chatOpenAI_0", + "position": { + "x": -636.2452233568264, + "y": 233.06616199339652 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 6, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "asyncOptions", + "loadMethod": "listModels", + "default": "gpt-3.5-turbo", + "id": "chatOpenAI_0-input-modelName-asyncOptions" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string" + }, + { + "label": "BaseOptions", + "name": "baseOptions", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-baseOptions-json" + }, + { + "label": "Allow Image Uploads", + "name": "allowImageUploads", + "type": "boolean", + "description": "Automatically uses gpt-4-vision-preview when image is being uploaded from chat. Only works with LLMChain, Conversation Chain, ReAct Agent, and Conversational Agent", + "default": false, + "optional": true, + "id": "chatOpenAI_0-input-allowImageUploads-boolean" + }, + { + "label": "Image Resolution", + "description": "This parameter controls the resolution in which the model views the image.", + "name": "imageResolution", + "type": "options", + "options": [ + { + "label": "Low", + "name": "low" + }, + { + "label": "High", + "name": "high" + }, + { + "label": "Auto", + "name": "auto" + } + ], + "default": "low", + "optional": false, + "additionalParams": true, + "id": "chatOpenAI_0-input-imageResolution-options" + } + ], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], + "inputs": { + "cache": "", + "modelName": "gpt-4o", + "temperature": "0", + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "", + "baseOptions": "", + "allowImageUploads": "", + "imageResolution": "low" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 669, + "selected": false, + "positionAbsolute": { + "x": -636.2452233568264, + "y": 233.06616199339652 + }, + "dragging": false + }, + { + "id": "customFunction_0", + "position": { + "x": 90.45254468977657, + "y": 626.487889256008 + }, + "type": "customNode", + "data": { + "id": "customFunction_0", + "label": "Custom JS Function", + "version": 1, + "name": "customFunction", + "type": "CustomFunction", + "baseClasses": ["CustomFunction", "Utilities"], + "category": "Utilities", + "description": "Execute custom javascript function", + "inputParams": [ + { + "label": "Input Variables", + "name": "functionInputVariables", + "description": "Input variables can be used in the function with prefix $. For example: $var", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "customFunction_0-input-functionInputVariables-json" + }, + { + "label": "Function Name", + "name": "functionName", + "type": "string", + "optional": true, + "placeholder": "My Function", + "id": "customFunction_0-input-functionName-string" + }, + { + "label": "Javascript Function", + "name": "javascriptFunction", + "type": "code", + "id": "customFunction_0-input-javascriptFunction-code" + } + ], + "inputAnchors": [], + "inputs": { + "functionInputVariables": "", + "functionName": "", + "javascriptFunction": "// Fetch schema info\nconst sqlSchema = `CREATE TABLE customers (\n customerNumber int NOT NULL,\n customerName varchar(50) NOT NULL,\n contactLastName varchar(50) NOT NULL,\n contactFirstName varchar(50) NOT NULL,\n phone varchar(50) NOT NULL,\n addressLine1 varchar(50) NOT NULL,\n addressLine2 varchar(50) DEFAULT NULL,\n city varchar(50) NOT NULL,\n state varchar(50) DEFAULT NULL,\n postalCode varchar(15) DEFAULT NULL,\n country varchar(50) NOT NULL,\n salesRepEmployeeNumber int DEFAULT NULL,\n creditLimit decimal(10,2) DEFAULT NULL,\n)`\n\nreturn sqlSchema;" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "description": "", + "options": [ + { + "id": "customFunction_0-output-output-string|number|boolean|json|array", + "name": "output", + "label": "Output", + "description": "", + "type": "string | number | boolean | json | array" + }, + { + "id": "customFunction_0-output-EndingNode-CustomFunction", + "name": "EndingNode", + "label": "Ending Node", + "description": "", + "type": "CustomFunction" + } + ], + "default": "output" + } + ], + "outputs": { + "output": "output" + }, + "selected": false + }, + "width": 300, + "height": 669, + "selected": false, + "positionAbsolute": { + "x": 90.45254468977657, + "y": 626.487889256008 + }, + "dragging": false + }, + { + "id": "customTool_0", + "position": { + "x": 823.759726626879, + "y": 87.97240806811993 + }, + "type": "customNode", + "data": { + "id": "customTool_0", + "label": "Custom Tool", + "version": 1, + "name": "customTool", + "type": "CustomTool", + "baseClasses": ["CustomTool", "Tool", "StructuredTool", "Runnable"], + "category": "Tools", + "description": "Use custom tool you've created in Flowise within chatflow", + "inputParams": [ + { + "label": "Select Tool", + "name": "selectedTool", + "type": "asyncOptions", + "loadMethod": "listTools", + "id": "customTool_0-input-selectedTool-asyncOptions" + } + ], + "inputAnchors": [], + "inputs": { + "selectedTool": "4d723d69-e854-4351-90c0-6385ce908213" + }, + "outputAnchors": [ + { + "id": "customTool_0-output-customTool-CustomTool|Tool|StructuredTool|Runnable", + "name": "customTool", + "label": "CustomTool", + "description": "Use custom tool you've created in Flowise within chatflow", + "type": "CustomTool | Tool | StructuredTool | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 285, + "selected": false, + "positionAbsolute": { + "x": 823.759726626879, + "y": 87.97240806811993 + }, + "dragging": false + }, + { + "id": "worker_2", + "position": { + "x": 1643.1366621404572, + "y": 253.12633995235484 + }, + "type": "customNode", + "data": { + "id": "worker_2", + "label": "Worker", + "version": 1, + "name": "worker", + "type": "Worker", + "baseClasses": ["Worker"], + "category": "Multi Agents", + "inputParams": [ + { + "label": "Worker Name", + "name": "workerName", + "type": "string", + "placeholder": "Worker", + "id": "worker_2-input-workerName-string" + }, + { + "label": "Worker Prompt", + "name": "workerPrompt", + "type": "string", + "rows": 4, + "default": "You are a research assistant who can search for up-to-date info using search engine.", + "id": "worker_2-input-workerPrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "worker_2-input-promptValues-json" + }, + { + "label": "Max Iterations", + "name": "maxIterations", + "type": "number", + "optional": true, + "id": "worker_2-input-maxIterations-number" + } + ], + "inputAnchors": [ + { + "label": "Tools", + "name": "tools", + "type": "Tool", + "list": true, + "optional": true, + "id": "worker_2-input-tools-Tool" + }, + { + "label": "Supervisor", + "name": "supervisor", + "type": "Supervisor", + "id": "worker_2-input-supervisor-Supervisor" + }, + { + "label": "Tool Calling Chat Model", + "name": "model", + "type": "BaseChatModel", + "optional": true, + "description": "Only compatible with models that are capable of function calling: ChatOpenAI, ChatMistral, ChatAnthropic, ChatGoogleGenerativeAI, ChatVertexAI, GroqChat. If not specified, supervisor's model will be used", + "id": "worker_2-input-model-BaseChatModel" + } + ], + "inputs": { + "workerName": "SQL Reviewer", + "workerPrompt": "As an SQL Code Reviewer at {company}, you play a crucial role in ensuring the accuracy, efficiency, and reliability of our SQL queries and database systems. Your expertise in SQL and best practices in database management is essential for maintaining high standards in our data operations.\n\nYour goal is to thoroughly review and validate the SQL queries developed by the SQL Expert to ensure they meet our performance and accuracy standards. Check for potential issues such as syntax errors, performance bottlenecks, and logical inaccuracies. Collaborate with the SQL Expert and SQL Executor to provide constructive feedback and suggest improvements where necessary.\n\nThe output should be a detailed code review report that includes an assessment of each SQL query's accuracy, performance, and correctness. Provide actionable feedback and suggestions to enhance the quality of the SQL code, ensuring it supports our data-driven initiatives effectively.", + "tools": [], + "supervisor": "{{supervisor_0.data.instance}}", + "model": "", + "promptValues": "{\"company\":\"Flowise Inc\"}", + "maxIterations": "" + }, + "outputAnchors": [ + { + "id": "worker_2-output-worker-Worker", + "name": "worker", + "label": "Worker", + "description": "", + "type": "Worker" + } + ], + "outputs": {}, + "selected": false + }, + "width": 300, + "height": 808, + "selected": false, + "positionAbsolute": { + "x": 1643.1366621404572, + "y": 253.12633995235484 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "supervisor_0", + "targetHandle": "supervisor_0-input-model-BaseChatModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-supervisor_0-supervisor_0-input-model-BaseChatModel" + }, + { + "source": "customFunction_0", + "sourceHandle": "customFunction_0-output-output-string|number|boolean|json|array", + "target": "worker_0", + "targetHandle": "worker_0-input-promptValues-json", + "type": "buttonedge", + "id": "customFunction_0-customFunction_0-output-output-string|number|boolean|json|array-worker_0-worker_0-input-promptValues-json" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_0", + "targetHandle": "worker_0-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_0-worker_0-input-supervisor-Supervisor" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_1", + "targetHandle": "worker_1-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_1-worker_1-input-supervisor-Supervisor" + }, + { + "source": "customTool_0", + "sourceHandle": "customTool_0-output-customTool-CustomTool|Tool|StructuredTool|Runnable", + "target": "worker_1", + "targetHandle": "worker_1-input-tools-Tool", + "type": "buttonedge", + "id": "customTool_0-customTool_0-output-customTool-CustomTool|Tool|StructuredTool|Runnable-worker_1-worker_1-input-tools-Tool" + }, + { + "source": "supervisor_0", + "sourceHandle": "supervisor_0-output-supervisor-Supervisor", + "target": "worker_2", + "targetHandle": "worker_2-input-supervisor-Supervisor", + "type": "buttonedge", + "id": "supervisor_0-supervisor_0-output-supervisor-Supervisor-worker_2-worker_2-input-supervisor-Supervisor" + } + ] +} diff --git a/packages/server/marketplaces/chatflows/Advanced Structured Output Parser.json b/packages/server/marketplaces/chatflows/Advanced Structured Output Parser.json index a7e765caf9e..9e193b11003 100644 --- a/packages/server/marketplaces/chatflows/Advanced Structured Output Parser.json +++ b/packages/server/marketplaces/chatflows/Advanced Structured Output Parser.json @@ -1,5 +1,7 @@ { "description": "Return response as a JSON structure as specified by a Zod schema", + "categories": "AdvancedStructuredOutputParser,ChatOpenAI,LLM Chain,Langchain", + "framework": "Langchain", "badge": "NEW", "nodes": [ { diff --git a/packages/server/package.json b/packages/server/package.json index 60526774788..e1b77b90b47 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.7.1", + "version": "1.7.2", "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 7c3b265fd71..8a54c1307d7 100644 --- a/packages/server/src/Interface.ts +++ b/packages/server/src/Interface.ts @@ -2,6 +2,8 @@ import { ICommonObject, IFileUpload, INode, INodeData as INodeDataFromComponent, export type MessageType = 'apiMessage' | 'userMessage' +export type ChatflowType = 'CHATFLOW' | 'MULTIAGENT' + export enum chatType { INTERNAL = 'INTERNAL', EXTERNAL = 'EXTERNAL' @@ -25,7 +27,9 @@ export interface IChatFlow { apikeyid?: string analytic?: string chatbotConfig?: string - apiConfig?: any + apiConfig?: string + category?: string + type?: ChatflowType } export interface IChatMessage { @@ -36,6 +40,7 @@ export interface IChatMessage { sourceDocuments?: string usedTools?: string fileAnnotations?: string + agentReasoning?: string fileUploads?: string chatType: string chatId: string @@ -212,6 +217,7 @@ export interface IncomingInput { stopNodeId?: string uploads?: IFileUpload[] leadEmail?: string + history?: IMessage[] } export interface IActiveChatflows { diff --git a/packages/server/src/controllers/chat-messages/index.ts b/packages/server/src/controllers/chat-messages/index.ts index 7c32fb4caff..8ed67399210 100644 --- a/packages/server/src/controllers/chat-messages/index.ts +++ b/packages/server/src/controllers/chat-messages/index.ts @@ -150,9 +150,25 @@ const removeAllChatMessages = async (req: Request, res: Response, next: NextFunc } } +const abortChatMessage = async (req: Request, res: Response, next: NextFunction) => { + try { + if (typeof req.params === 'undefined' || !req.params.chatflowid || !req.params.chatid) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: chatMessagesController.abortChatMessage - chatflowid or chatid not provided!` + ) + } + await chatMessagesService.abortChatMessage(req.params.chatid, req.params.chatflowid) + return res.json({ status: 200, message: 'Chat message aborted' }) + } catch (error) { + next(error) + } +} + export default { createChatMessage, getAllChatMessages, getAllInternalChatMessages, - removeAllChatMessages + removeAllChatMessages, + abortChatMessage } diff --git a/packages/server/src/controllers/chatflows/index.ts b/packages/server/src/controllers/chatflows/index.ts index 8923bf55bbf..dc86090a020 100644 --- a/packages/server/src/controllers/chatflows/index.ts +++ b/packages/server/src/controllers/chatflows/index.ts @@ -5,6 +5,7 @@ import { createRateLimiter } from '../../utils/rateLimit' import { getApiKey } from '../../utils/apiKey' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { StatusCodes } from 'http-status-codes' +import { ChatflowType } from '../../Interface' const checkIfChatflowIsValidForStreaming = async (req: Request, res: Response, next: NextFunction) => { try { @@ -50,7 +51,7 @@ const deleteChatflow = async (req: Request, res: Response, next: NextFunction) = const getAllChatflows = async (req: Request, res: Response, next: NextFunction) => { try { - const apiResponse = await chatflowsService.getAllChatflows() + const apiResponse = await chatflowsService.getAllChatflows(req.query?.type as ChatflowType) return res.json(apiResponse) } catch (error) { next(error) @@ -60,17 +61,17 @@ const getAllChatflows = async (req: Request, res: Response, next: NextFunction) // Get specific chatflow via api key const getChatflowByApiKey = async (req: Request, res: Response, next: NextFunction) => { try { - if (typeof req.params === 'undefined' || !req.params.apiKey) { + if (typeof req.params === 'undefined' || !req.params.apikey) { throw new InternalFlowiseError( StatusCodes.PRECONDITION_FAILED, - `Error: chatflowsRouter.getChatflowByApiKey - apiKey not provided!` + `Error: chatflowsRouter.getChatflowByApiKey - apikey not provided!` ) } - const apiKey = await getApiKey(req.params.apiKey) - if (!apiKey) { + const apikey = await getApiKey(req.params.apikey) + if (!apikey) { return res.status(401).send('Unauthorized') } - const apiResponse = await chatflowsService.getChatflowByApiKey(apiKey.id) + const apiResponse = await chatflowsService.getChatflowByApiKey(apikey.id) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/database/entities/ChatFlow.ts b/packages/server/src/database/entities/ChatFlow.ts index d654128d976..e0d2da50229 100644 --- a/packages/server/src/database/entities/ChatFlow.ts +++ b/packages/server/src/database/entities/ChatFlow.ts @@ -1,6 +1,6 @@ /* eslint-disable */ import { Entity, Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn } from 'typeorm' -import { IChatFlow } from '../../Interface' +import { ChatflowType, IChatFlow } from '../../Interface' @Entity() export class ChatFlow implements IChatFlow { @@ -34,6 +34,12 @@ export class ChatFlow implements IChatFlow { @Column({ nullable: true, type: 'text' }) speechToText?: string + @Column({ nullable: true, type: 'text' }) + category?: string + + @Column({ nullable: true, type: 'text' }) + type?: ChatflowType + @Column({ type: 'timestamp' }) @CreateDateColumn() createdDate: Date @@ -41,7 +47,4 @@ export class ChatFlow implements IChatFlow { @Column({ type: 'timestamp' }) @UpdateDateColumn() updatedDate: Date - - @Column({ nullable: true, type: 'text' }) - category?: string } diff --git a/packages/server/src/database/entities/ChatMessage.ts b/packages/server/src/database/entities/ChatMessage.ts index 4cc84983f55..af7ccb0fc5c 100644 --- a/packages/server/src/database/entities/ChatMessage.ts +++ b/packages/server/src/database/entities/ChatMessage.ts @@ -26,6 +26,9 @@ export class ChatMessage implements IChatMessage { @Column({ nullable: true, type: 'text' }) fileAnnotations?: string + @Column({ nullable: true, type: 'text' }) + agentReasoning?: string + @Column({ nullable: true, type: 'text' }) fileUploads?: string diff --git a/packages/server/src/database/migrations/mysql/1714679514451-AddAgentReasoningToChatMessage.ts b/packages/server/src/database/migrations/mysql/1714679514451-AddAgentReasoningToChatMessage.ts new file mode 100644 index 00000000000..c19872567c0 --- /dev/null +++ b/packages/server/src/database/migrations/mysql/1714679514451-AddAgentReasoningToChatMessage.ts @@ -0,0 +1,12 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddAgentReasoningToChatMessage1714679514451 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const columnExists = await queryRunner.hasColumn('chat_message', 'agentReasoning') + if (!columnExists) queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`agentReasoning\` LONGTEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`chat_message\` DROP COLUMN \`agentReasoning\`;`) + } +} diff --git a/packages/server/src/database/migrations/mysql/1766759476232-AddTypeToChatFlow.ts b/packages/server/src/database/migrations/mysql/1766759476232-AddTypeToChatFlow.ts new file mode 100644 index 00000000000..f19e4ad5664 --- /dev/null +++ b/packages/server/src/database/migrations/mysql/1766759476232-AddTypeToChatFlow.ts @@ -0,0 +1,12 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddTypeToChatFlow1766759476232 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const columnExists = await queryRunner.hasColumn('chat_flow', 'type') + if (!columnExists) queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`type\` TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`chat_flow\` DROP COLUMN \`type\`;`) + } +} diff --git a/packages/server/src/database/migrations/mysql/index.ts b/packages/server/src/database/migrations/mysql/index.ts index 65de0bb4abe..f8c594ca81e 100644 --- a/packages/server/src/database/migrations/mysql/index.ts +++ b/packages/server/src/database/migrations/mysql/index.ts @@ -18,6 +18,8 @@ import { AddFeedback1707213626553 } from './1707213626553-AddFeedback' import { AddDocumentStore1711637331047 } from './1711637331047-AddDocumentStore' import { AddLead1710832127079 } from './1710832127079-AddLead' import { AddLeadToChatMessage1711538023578 } from './1711538023578-AddLeadToChatMessage' +import { AddAgentReasoningToChatMessage1714679514451 } from './1714679514451-AddAgentReasoningToChatMessage' +import { AddTypeToChatFlow1766759476232 } from './1766759476232-AddTypeToChatFlow' export const mysqlMigrations = [ Init1693840429259, @@ -32,12 +34,14 @@ export const mysqlMigrations = [ AddUsedToolsToChatMessage1699481607341, AddCategoryToChatFlow1699900910291, AddFileAnnotationsToChatMessage1700271021237, - AddFileUploadsToChatMessage1701788586491, AddVariableEntity1699325775451, + AddFileUploadsToChatMessage1701788586491, AddSpeechToText1706364937060, AddUpsertHistoryEntity1709814301358, AddFeedback1707213626553, AddDocumentStore1711637331047, AddLead1710832127079, - AddLeadToChatMessage1711538023578 + AddLeadToChatMessage1711538023578, + AddAgentReasoningToChatMessage1714679514451, + AddTypeToChatFlow1766759476232 ] diff --git a/packages/server/src/database/migrations/postgres/1714679514451-AddAgentReasoningToChatMessage.ts b/packages/server/src/database/migrations/postgres/1714679514451-AddAgentReasoningToChatMessage.ts new file mode 100644 index 00000000000..d0a76b552bf --- /dev/null +++ b/packages/server/src/database/migrations/postgres/1714679514451-AddAgentReasoningToChatMessage.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddAgentReasoningToChatMessage1714679514451 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_message" ADD COLUMN IF NOT EXISTS "agentReasoning" TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "agentReasoning";`) + } +} diff --git a/packages/server/src/database/migrations/postgres/1766759476232-AddTypeToChatFlow.ts b/packages/server/src/database/migrations/postgres/1766759476232-AddTypeToChatFlow.ts new file mode 100644 index 00000000000..ad79a1973ce --- /dev/null +++ b/packages/server/src/database/migrations/postgres/1766759476232-AddTypeToChatFlow.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddTypeToChatFlow1766759476232 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN IF NOT EXISTS "type" TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" DROP COLUMN "type";`) + } +} diff --git a/packages/server/src/database/migrations/postgres/index.ts b/packages/server/src/database/migrations/postgres/index.ts index b366071a6f8..abcf8173eb0 100644 --- a/packages/server/src/database/migrations/postgres/index.ts +++ b/packages/server/src/database/migrations/postgres/index.ts @@ -19,6 +19,8 @@ import { FieldTypes1710497452584 } from './1710497452584-FieldTypes' import { AddDocumentStore1711637331047 } from './1711637331047-AddDocumentStore' import { AddLead1710832137905 } from './1710832137905-AddLead' import { AddLeadToChatMessage1711538016098 } from './1711538016098-AddLeadToChatMessage' +import { AddAgentReasoningToChatMessage1714679514451 } from './1714679514451-AddAgentReasoningToChatMessage' +import { AddTypeToChatFlow1766759476232 } from './1766759476232-AddTypeToChatFlow' export const postgresMigrations = [ Init1693891895163, @@ -33,13 +35,15 @@ export const postgresMigrations = [ AddUsedToolsToChatMessage1699481607341, AddCategoryToChatFlow1699900910291, AddFileAnnotationsToChatMessage1700271021237, - AddFileUploadsToChatMessage1701788586491, AddVariableEntity1699325775451, + AddFileUploadsToChatMessage1701788586491, AddSpeechToText1706364937060, AddUpsertHistoryEntity1709814301358, AddFeedback1707213601923, FieldTypes1710497452584, AddDocumentStore1711637331047, AddLead1710832137905, - AddLeadToChatMessage1711538016098 + AddLeadToChatMessage1711538016098, + AddAgentReasoningToChatMessage1714679514451, + AddTypeToChatFlow1766759476232 ] diff --git a/packages/server/src/database/migrations/sqlite/1714679514451-AddAgentReasoningToChatMessage.ts b/packages/server/src/database/migrations/sqlite/1714679514451-AddAgentReasoningToChatMessage.ts new file mode 100644 index 00000000000..8a1c8ea87dd --- /dev/null +++ b/packages/server/src/database/migrations/sqlite/1714679514451-AddAgentReasoningToChatMessage.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddAgentReasoningToChatMessage1714679514451 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_message" ADD COLUMN "agentReasoning" TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "agentReasoning";`) + } +} diff --git a/packages/server/src/database/migrations/sqlite/1766759476232-AddTypeToChatFlow.ts b/packages/server/src/database/migrations/sqlite/1766759476232-AddTypeToChatFlow.ts new file mode 100644 index 00000000000..f41d9ed9f93 --- /dev/null +++ b/packages/server/src/database/migrations/sqlite/1766759476232-AddTypeToChatFlow.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddTypeToChatFlow1766759476232 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "type" TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" DROP COLUMN "type";`) + } +} diff --git a/packages/server/src/database/migrations/sqlite/index.ts b/packages/server/src/database/migrations/sqlite/index.ts index 22d3e790466..35237efd59c 100644 --- a/packages/server/src/database/migrations/sqlite/index.ts +++ b/packages/server/src/database/migrations/sqlite/index.ts @@ -18,6 +18,8 @@ import { AddFeedback1707213619308 } from './1707213619308-AddFeedback' import { AddDocumentStore1711637331047 } from './1711637331047-AddDocumentStore' import { AddLead1710832117612 } from './1710832117612-AddLead' import { AddLeadToChatMessage1711537986113 } from './1711537986113-AddLeadToChatMessage' +import { AddAgentReasoningToChatMessage1714679514451 } from './1714679514451-AddAgentReasoningToChatMessage' +import { AddTypeToChatFlow1766759476232 } from './1766759476232-AddTypeToChatFlow' export const sqliteMigrations = [ Init1693835579790, @@ -32,12 +34,14 @@ export const sqliteMigrations = [ AddUsedToolsToChatMessage1699481607341, AddCategoryToChatFlow1699900910291, AddFileAnnotationsToChatMessage1700271021237, - AddFileUploadsToChatMessage1701788586491, AddVariableEntity1699325775451, + AddFileUploadsToChatMessage1701788586491, AddSpeechToText1706364937060, AddUpsertHistoryEntity1709814301358, AddFeedback1707213619308, AddDocumentStore1711637331047, AddLead1710832117612, - AddLeadToChatMessage1711537986113 + AddLeadToChatMessage1711537986113, + AddAgentReasoningToChatMessage1714679514451, + AddTypeToChatFlow1766759476232 ] diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 387460cb95f..36bfd3d1f06 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -43,40 +43,39 @@ export class App { async initDatabase() { // Initialize database - this.AppDataSource.initialize() - .then(async () => { - logger.info('📦 [server]: Data Source is initializing...') + try { + await this.AppDataSource.initialize() + logger.info('📦 [server]: Data Source is initializing...') - // Run Migrations Scripts - await this.AppDataSource.runMigrations({ transaction: 'each' }) + // Run Migrations Scripts + await this.AppDataSource.runMigrations({ transaction: 'each' }) - // Initialize nodes pool - this.nodesPool = new NodesPool() - await this.nodesPool.initialize() + // Initialize nodes pool + this.nodesPool = new NodesPool() + await this.nodesPool.initialize() - // Initialize chatflow pool - this.chatflowPool = new ChatflowPool() + // Initialize chatflow pool + this.chatflowPool = new ChatflowPool() - // Initialize API keys - await getAPIKeys() + // Initialize API keys + await getAPIKeys() - // Initialize encryption key - await getEncryptionKey() + // Initialize encryption key + await getEncryptionKey() - // Initialize Rate Limit - const AllChatFlow: IChatFlow[] = await getAllChatFlow() - await initializeRateLimiter(AllChatFlow) + // Initialize Rate Limit + const AllChatFlow: IChatFlow[] = await getAllChatFlow() + await initializeRateLimiter(AllChatFlow) - // Initialize cache pool - this.cachePool = new CachePool() + // Initialize cache pool + this.cachePool = new CachePool() - // Initialize telemetry - this.telemetry = new Telemetry() - logger.info('📦 [server]: Data Source has been initialized!') - }) - .catch((err) => { - logger.error('❌ [server]: Error during Data Source initialization:', err) - }) + // Initialize telemetry + this.telemetry = new Telemetry() + logger.info('📦 [server]: Data Source has been initialized!') + } catch (error) { + logger.error('❌ [server]: Error during Data Source initialization:', error) + } } async config(socketIO?: Server) { diff --git a/packages/server/src/routes/chat-messages/index.ts b/packages/server/src/routes/chat-messages/index.ts index 64dacb13005..ca90abcf79f 100644 --- a/packages/server/src/routes/chat-messages/index.ts +++ b/packages/server/src/routes/chat-messages/index.ts @@ -9,6 +9,7 @@ router.post(['/', '/:id'], chatMessageController.createChatMessage) router.get(['/', '/:id'], chatMessageController.getAllChatMessages) // UPDATE +router.put(['/abort/', '/abort/:chatflowid/:chatid'], chatMessageController.abortChatMessage) // DELETE router.delete(['/', '/:id'], chatMessageController.removeAllChatMessages) diff --git a/packages/server/src/services/apikey/index.ts b/packages/server/src/services/apikey/index.ts index 0bb09d02cd3..06c4f3d5ade 100644 --- a/packages/server/src/services/apikey/index.ts +++ b/packages/server/src/services/apikey/index.ts @@ -46,7 +46,7 @@ const deleteApiKey = async (id: string) => { } } -const verifyApiKey = async (paramApiKey: string): Promise => { +const verifyApiKey = async (paramApiKey: string): Promise => { try { const apiKey = await getApiKey(paramApiKey) if (!apiKey) { diff --git a/packages/server/src/services/chat-messages/index.ts b/packages/server/src/services/chat-messages/index.ts index 8782b9bee07..39d0606c7c8 100644 --- a/packages/server/src/services/chat-messages/index.ts +++ b/packages/server/src/services/chat-messages/index.ts @@ -1,4 +1,4 @@ -import { FindOptionsWhere } from 'typeorm' +import { DeleteResult, FindOptionsWhere } from 'typeorm' import { StatusCodes } from 'http-status-codes' import { chatType, IChatMessage } from '../../Interface' import { utilGetChatMessage } from '../../utils/getChatMessage' @@ -36,7 +36,7 @@ const getAllChatMessages = async ( endDate?: string, messageId?: string, feedback?: boolean -): Promise => { +): Promise => { try { const dbResponse = await utilGetChatMessage( chatflowId, @@ -71,7 +71,7 @@ const getAllInternalChatMessages = async ( endDate?: string, messageId?: string, feedback?: boolean -): Promise => { +): Promise => { try { const dbResponse = await utilGetChatMessage( chatflowId, @@ -94,7 +94,11 @@ const getAllInternalChatMessages = async ( } } -const removeAllChatMessages = async (chatId: string, chatflowid: string, deleteOptions: FindOptionsWhere): Promise => { +const removeAllChatMessages = async ( + chatId: string, + chatflowid: string, + deleteOptions: FindOptionsWhere +): Promise => { try { const appServer = getRunningExpressApp() @@ -120,9 +124,32 @@ const removeAllChatMessages = async (chatId: string, chatflowid: string, deleteO } } +const abortChatMessage = async (chatId: string, chatflowid: string) => { + try { + const appServer = getRunningExpressApp() + + const endingNodeData = appServer.chatflowPool.activeChatflows[`${chatflowid}_${chatId}`]?.endingNodeData as any + + if (endingNodeData && endingNodeData.signal) { + try { + endingNodeData.signal.abort() + await appServer.chatflowPool.remove(`${chatflowid}_${chatId}`) + } catch (e) { + logger.error(`[server]: Error aborting chat message for ${chatflowid}, chatId ${chatId}: ${e}`) + } + } + } catch (error) { + throw new InternalFlowiseError( + StatusCodes.INTERNAL_SERVER_ERROR, + `Error: chatMessagesService.abortChatMessage - ${getErrorMessage(error)}` + ) + } +} + export default { createChatMessage, getAllChatMessages, getAllInternalChatMessages, - removeAllChatMessages + removeAllChatMessages, + abortChatMessage } diff --git a/packages/server/src/services/chatflows/index.ts b/packages/server/src/services/chatflows/index.ts index 725071e243d..54e7ee47cda 100644 --- a/packages/server/src/services/chatflows/index.ts +++ b/packages/server/src/services/chatflows/index.ts @@ -1,7 +1,7 @@ import { StatusCodes } from 'http-status-codes' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { getRunningExpressApp } from '../../utils/getRunningExpressApp' -import { IChatFlow } from '../../Interface' +import { ChatflowType, IChatFlow } from '../../Interface' import { ChatFlow } from '../../database/entities/ChatFlow' import { getAppVersion, getTelemetryFlowObj, isFlowValidForStream, constructGraphs, getEndingNodes } from '../../utils' import logger from '../../utils/logger' @@ -47,6 +47,11 @@ const checkIfChatflowIsValidForStreaming = async (chatflowId: string): Promise node.data.category === 'Multi Agents').length > 0) { + return { isStreaming: true } + } + const dbResponse = { isStreaming: isStreaming } return dbResponse } catch (error) { @@ -99,11 +104,14 @@ const deleteChatflow = async (chatflowId: string): Promise => { } } -const getAllChatflows = async (): Promise => { +const getAllChatflows = async (type?: ChatflowType): Promise => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).find() - return dbResponse + if (type === 'MULTIAGENT') { + return dbResponse.filter((chatflow) => chatflow.type === type) + } + return dbResponse.filter((chatflow) => chatflow.type === 'CHATFLOW' || !chatflow.type) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, @@ -114,6 +122,7 @@ const getAllChatflows = async (): Promise => { const getChatflowByApiKey = async (apiKeyId: string): Promise => { try { + // Here we only get chatflows that are bounded by the apikeyid and chatflows that are not bounded by any apikey const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow) .createQueryBuilder('cf') diff --git a/packages/server/src/services/documentstore/index.ts b/packages/server/src/services/documentstore/index.ts index d19860d4a94..2367a9330bd 100644 --- a/packages/server/src/services/documentstore/index.ts +++ b/packages/server/src/services/documentstore/index.ts @@ -2,7 +2,7 @@ import { getRunningExpressApp } from '../../utils/getRunningExpressApp' import { DocumentStore } from '../../database/entities/DocumentStore' // @ts-ignore import { - addFileToStorage, + addSingleFileToStorage, getFileFromStorage, ICommonObject, IDocument, @@ -343,7 +343,7 @@ const _saveFileToStorage = async (fileBase64: string, entity: DocumentStore) => if (mimePrefix) { mime = mimePrefix.split(';')[0].split(':')[1] } - await addFileToStorage(mime, bf, filename, DOCUMENT_STORE_BASE_FOLDER, entity.id) + await addSingleFileToStorage(mime, bf, filename, DOCUMENT_STORE_BASE_FOLDER, entity.id) return { id: uuidv4(), name: filename, diff --git a/packages/server/src/services/marketplaces/index.ts b/packages/server/src/services/marketplaces/index.ts index 54e43899cb5..1858f7696c6 100644 --- a/packages/server/src/services/marketplaces/index.ts +++ b/packages/server/src/services/marketplaces/index.ts @@ -44,6 +44,25 @@ const getAllTemplates = async () => { } templates.push(template) }) + + marketplaceDir = path.join(__dirname, '..', '..', '..', 'marketplaces', 'agentflows') + jsonsInDir = fs.readdirSync(marketplaceDir).filter((file) => path.extname(file) === '.json') + jsonsInDir.forEach((file, index) => { + const filePath = path.join(__dirname, '..', '..', '..', 'marketplaces', 'agentflows', file) + const fileData = fs.readFileSync(filePath) + const fileDataObj = JSON.parse(fileData.toString()) + const template = { + id: index, + templateName: file.split('.json')[0], + flowData: fileData.toString(), + badge: fileDataObj?.badge, + framework: fileDataObj?.framework, + categories: fileDataObj?.categories, + type: 'Agentflow', + description: fileDataObj?.description || '' + } + templates.push(template) + }) const sortedTemplates = templates.sort((a, b) => a.templateName.localeCompare(b.templateName)) const FlowiseDocsQnAIndex = sortedTemplates.findIndex((tmp) => tmp.templateName === 'Flowise Docs QnA') if (FlowiseDocsQnAIndex > 0) { diff --git a/packages/server/src/utils/buildAgentGraph.ts b/packages/server/src/utils/buildAgentGraph.ts new file mode 100644 index 00000000000..9ada9eea9ac --- /dev/null +++ b/packages/server/src/utils/buildAgentGraph.ts @@ -0,0 +1,345 @@ +import { + ICommonObject, + IMultiAgentNode, + IAgentReasoning, + ITeamState, + ConsoleCallbackHandler, + additionalCallbacks +} from 'flowise-components' +import { IChatFlow, IComponentNodes, IDepthQueue, IReactFlowNode, IReactFlowObject } from '../Interface' +import { Server } from 'socket.io' +import { buildFlow, getStartingNodes, getEndingNodes, constructGraphs, databaseEntities } from '../utils' +import { getRunningExpressApp } from './getRunningExpressApp' +import logger from './logger' +import { StateGraph, END } from '@langchain/langgraph' +import { BaseMessage, HumanMessage } from '@langchain/core/messages' +import { cloneDeep, flatten } from 'lodash' +import { replaceInputsWithConfig, resolveVariables } from '.' +import { StatusCodes } from 'http-status-codes' +import { InternalFlowiseError } from '../errors/internalFlowiseError' +import { getErrorMessage } from '../errors/utils' + +/** + * Build Agent Graph + * @param {IChatFlow} chatflow + * @param {string} chatId + * @param {string} sessionId + * @param {ICommonObject} incomingInput + * @param {string} baseURL + * @param {Server} socketIO + */ +export const buildAgentGraph = async ( + chatflow: IChatFlow, + chatId: string, + sessionId: string, + incomingInput: ICommonObject, + baseURL?: string, + socketIO?: Server +): Promise => { + try { + const appServer = getRunningExpressApp() + const chatflowid = chatflow.id + + /*** Get chatflows and prepare data ***/ + const flowData = chatflow.flowData + const parsedFlowData: IReactFlowObject = JSON.parse(flowData) + const nodes = parsedFlowData.nodes + const edges = parsedFlowData.edges + + /*** Get Ending Node with Directed Graph ***/ + const { graph, nodeDependencies } = constructGraphs(nodes, edges) + const directedGraph = graph + + const endingNodes = getEndingNodes(nodeDependencies, directedGraph, nodes) + + /*** Get Starting Nodes with Reversed Graph ***/ + const constructedObj = constructGraphs(nodes, edges, { isReversed: true }) + const nonDirectedGraph = constructedObj.graph + let startingNodeIds: string[] = [] + let depthQueue: IDepthQueue = {} + const endingNodeIds = endingNodes.map((n) => n.id) + for (const endingNodeId of endingNodeIds) { + const resx = getStartingNodes(nonDirectedGraph, endingNodeId) + startingNodeIds.push(...resx.startingNodeIds) + depthQueue = Object.assign(depthQueue, resx.depthQueue) + } + startingNodeIds = [...new Set(startingNodeIds)] + + // Initialize nodes like ChatModels, Tools, etc. + const reactFlowNodes = await buildFlow( + startingNodeIds, + nodes, + edges, + graph, + depthQueue, + appServer.nodesPool.componentNodes, + incomingInput.question, + [], + chatId, + sessionId, + chatflowid, + appServer.AppDataSource, + incomingInput?.overrideConfig, + appServer.cachePool, + false, + undefined, + incomingInput.uploads, + baseURL + ) + + const options = { + chatId, + sessionId, + chatflowid, + logger, + analytic: chatflow.analytic, + appDataSource: appServer.AppDataSource, + databaseEntities: databaseEntities, + cachePool: appServer.cachePool, + uploads: incomingInput.uploads, + baseURL, + signal: new AbortController() + } + + let streamResults + let finalResult = '' + let agentReasoning: IAgentReasoning[] = [] + + const workerNodes: IReactFlowNode[] = reactFlowNodes.filter((node: IReactFlowNode) => node.data.name === 'worker') + const supervisorNodes: IReactFlowNode[] = reactFlowNodes.filter((node: IReactFlowNode) => node.data.name === 'supervisor') + + const mapNameToLabel: Record = {} + + for (const node of [...workerNodes, ...supervisorNodes]) { + mapNameToLabel[node.data.instance.name] = node.data.instance.label + } + + try { + streamResults = await compileGraph( + chatflow, + mapNameToLabel, + reactFlowNodes, + endingNodeIds, + appServer.nodesPool.componentNodes, + options, + startingNodeIds, + incomingInput.question, + incomingInput?.overrideConfig + ) + + if (streamResults) { + let isStreamingStarted = false + for await (const output of await streamResults) { + if (!output?.__end__) { + const agentName = Object.keys(output)[0] + const usedTools = output[agentName]?.messages + ? output[agentName].messages.map((msg: any) => msg.additional_kwargs?.usedTools) + : [] + const sourceDocuments = output[agentName]?.messages + ? output[agentName].messages.map((msg: any) => msg.additional_kwargs?.sourceDocuments) + : [] + const messages = output[agentName]?.messages ? output[agentName].messages.map((msg: any) => msg.content) : [] + const reasoning = { + agentName: mapNameToLabel[agentName], + messages, + next: output[agentName]?.next, + instructions: output[agentName]?.instructions, + usedTools: flatten(usedTools), + sourceDocuments: flatten(sourceDocuments) + } + agentReasoning.push(reasoning) + if (socketIO && incomingInput.socketIOClientId) { + if (!isStreamingStarted) { + isStreamingStarted = true + socketIO.to(incomingInput.socketIOClientId).emit('start', JSON.stringify(agentReasoning)) + } + + socketIO.to(incomingInput.socketIOClientId).emit('agentReasoning', JSON.stringify(agentReasoning)) + + // Send loading next agent indicator + if (reasoning.next && reasoning.next !== 'FINISH' && reasoning.next !== 'END') { + socketIO + .to(incomingInput.socketIOClientId) + .emit('nextAgent', mapNameToLabel[reasoning.next] || reasoning.next) + } + } + } else { + finalResult = output.__end__.messages.length ? output.__end__.messages.pop()?.content : '' + if (Array.isArray(finalResult)) finalResult = output.__end__.instructions + + if (finalResult === incomingInput.question) { + const supervisorNode = reactFlowNodes.find((node: IReactFlowNode) => node.data.name === 'supervisor') + const llm = supervisorNode?.data?.instance?.llm + if (llm) { + const res = await llm.invoke(incomingInput.question) + finalResult = res?.content + } + } + + if (socketIO && incomingInput.socketIOClientId) { + socketIO.to(incomingInput.socketIOClientId).emit('token', finalResult) + } + } + } + + return { finalResult, agentReasoning } + } + } catch (e) { + if (socketIO && incomingInput.socketIOClientId) { + socketIO.to(incomingInput.socketIOClientId).emit('abort') + } + return { finalResult, agentReasoning } + } + return streamResults + } catch (e) { + logger.error('[server]: Error:', e) + throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error buildAgentGraph - ${getErrorMessage(e)}`) + } +} + +/** + * Compile Graph + * @param {IChatFlow} chatflow + * @param {Record} mapNameToLabel + * @param {IReactFlowNode[]} reactflowNodes + * @param {string[]} workerNodeIds + * @param {IComponentNodes} componentNodes + * @param {ICommonObject} options + * @param {string[]} startingNodeIds + * @param {string} question + * @param {ICommonObject} overrideConfig + */ +const compileGraph = async ( + chatflow: IChatFlow, + mapNameToLabel: Record, + reactflowNodes: IReactFlowNode[] = [], + workerNodeIds: string[], + componentNodes: IComponentNodes, + options: ICommonObject, + startingNodeIds: string[], + question: string, + overrideConfig?: ICommonObject +) => { + const appServer = getRunningExpressApp() + const channels: ITeamState = { + messages: { + value: (x: BaseMessage[], y: BaseMessage[]) => x.concat(y), + default: () => [] + }, + next: 'initialState', + instructions: "Solve the user's request.", + team_members: [] + } + + const workflowGraph = new StateGraph({ + //@ts-ignore + channels + }) + + const workerNodes = reactflowNodes.filter((node) => workerNodeIds.includes(node.data.id)) + + let supervisorWorkers: { [key: string]: IMultiAgentNode[] } = {} + + // Init worker nodes + for (const workerNode of workerNodes) { + const nodeInstanceFilePath = componentNodes[workerNode.data.name].filePath as string + const nodeModule = await import(nodeInstanceFilePath) + const newNodeInstance = new nodeModule.nodeClass() + + let flowNodeData = cloneDeep(workerNode.data) + if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig) + flowNodeData = resolveVariables(flowNodeData, reactflowNodes, question, []) + + try { + const workerResult: IMultiAgentNode = await newNodeInstance.init(flowNodeData, question, options) + const parentSupervisor = workerResult.parentSupervisorName + if (!parentSupervisor || workerResult.type !== 'worker') continue + if (Object.prototype.hasOwnProperty.call(supervisorWorkers, parentSupervisor)) { + supervisorWorkers[parentSupervisor].push(workerResult) + } else { + supervisorWorkers[parentSupervisor] = [workerResult] + } + + workflowGraph.addNode(workerResult.name, workerResult.node) + } catch (e) { + throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error initialize worker nodes - ${getErrorMessage(e)}`) + } + } + + // Init supervisor nodes + for (const supervisor in supervisorWorkers) { + const supervisorInputLabel = mapNameToLabel[supervisor] + const supervisorNode = reactflowNodes.find((node) => supervisorInputLabel === node.data.inputs?.supervisorName) + if (!supervisorNode) continue + + const nodeInstanceFilePath = componentNodes[supervisorNode.data.name].filePath as string + const nodeModule = await import(nodeInstanceFilePath) + const newNodeInstance = new nodeModule.nodeClass() + + let flowNodeData = cloneDeep(supervisorNode.data) + + if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig) + flowNodeData = resolveVariables(flowNodeData, reactflowNodes, question, []) + + if (flowNodeData.inputs) flowNodeData.inputs.workerNodes = supervisorWorkers[supervisor] + + try { + const supervisorResult: IMultiAgentNode = await newNodeInstance.init(flowNodeData, question, options) + if (!supervisorResult.workers?.length) continue + + if (supervisorResult.moderations && supervisorResult.moderations.length > 0) { + try { + for (const moderation of supervisorResult.moderations) { + question = await moderation.checkForViolations(question) + } + } catch (e) { + throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, getErrorMessage(e)) + } + } + + workflowGraph.addNode(supervisorResult.name, supervisorResult.node) + + for (const worker of supervisorResult.workers) { + workflowGraph.addEdge(worker, supervisorResult.name) + } + + let conditionalEdges: { [key: string]: string } = {} + for (let i = 0; i < supervisorResult.workers.length; i++) { + conditionalEdges[supervisorResult.workers[i]] = supervisorResult.workers[i] + } + + workflowGraph.addConditionalEdges(supervisorResult.name, (x: ITeamState) => x.next, { + ...conditionalEdges, + FINISH: END + }) + + workflowGraph.setEntryPoint(supervisorResult.name) + + // Add agentflow to pool + ;(workflowGraph as any).signal = options.signal + appServer.chatflowPool.add( + `${chatflow.id}_${options.chatId}`, + workflowGraph as any, + reactflowNodes.filter((node) => startingNodeIds.includes(node.id)), + overrideConfig + ) + + // TODO: add persistence + // const memory = new MemorySaver() + const graph = workflowGraph.compile() + + const loggerHandler = new ConsoleCallbackHandler(logger) + const callbacks = await additionalCallbacks(flowNodeData, options) + + // Return stream result as we should only have 1 supervisor + return await graph.stream( + { + messages: [new HumanMessage({ content: question })] + }, + { recursionLimit: supervisorResult?.recursionLimit ?? 100, callbacks: [loggerHandler, ...callbacks] } + ) + } catch (e) { + throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error initialize supervisor nodes - ${getErrorMessage(e)}`) + } + } +} diff --git a/packages/server/src/utils/buildChatflow.ts b/packages/server/src/utils/buildChatflow.ts index 3ffefff326e..3fcf03fac2f 100644 --- a/packages/server/src/utils/buildChatflow.ts +++ b/packages/server/src/utils/buildChatflow.ts @@ -1,7 +1,18 @@ import { Request } from 'express' -import { IFileUpload, convertSpeechToText, ICommonObject, addFileToStorage } from 'flowise-components' +import { IFileUpload, convertSpeechToText, ICommonObject, addSingleFileToStorage, addArrayFilesToStorage } from 'flowise-components' import { StatusCodes } from 'http-status-codes' -import { IncomingInput, IMessage, INodeData, IReactFlowObject, IReactFlowNode, IDepthQueue, chatType, IChatMessage } from '../Interface' +import { + IncomingInput, + IMessage, + INodeData, + IReactFlowObject, + IReactFlowNode, + IDepthQueue, + chatType, + IChatMessage, + IChatFlow, + IReactFlowEdge +} from '../Interface' import { InternalFlowiseError } from '../errors/internalFlowiseError' import { ChatFlow } from '../database/entities/ChatFlow' import { Server } from 'socket.io' @@ -30,6 +41,8 @@ import { omit } from 'lodash' import * as fs from 'fs' import logger from './logger' import { utilAddChatMessage } from './addChatMesage' +import { buildAgentGraph } from './buildAgentGraph' +import { getErrorMessage } from '../errors/utils' /** * Build Chatflow @@ -41,6 +54,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter try { const appServer = getRunningExpressApp() const chatflowid = req.params.id + const baseURL = `${req.protocol}://${req.get('host')}` + let incomingInput: IncomingInput = req.body let nodeToExecuteData: INodeData const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ @@ -71,14 +86,15 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter const splitDataURI = upload.data.split(',') const bf = Buffer.from(splitDataURI.pop() || '', 'base64') const mime = splitDataURI[0].split(':')[1].split(';')[0] - await addFileToStorage(mime, bf, filename, chatflowid, chatId) + await addSingleFileToStorage(mime, bf, filename, chatflowid, chatId) upload.type = 'stored-file' // Omit upload.data since we don't store the content in database fileUploads[i] = omit(upload, ['data']) } // Run Speech to Text conversion - if (upload.mime === 'audio/webm' || upload.mime === 'audio/mp4') { + if (upload.mime === 'audio/webm' || upload.mime === 'audio/mp4' || upload.mime === 'audio/ogg') { + logger.debug(`Attempting a speech to text conversion...`) let speechToTextConfig: ICommonObject = {} if (chatflow.speechToText) { const speechToTextProviders = JSON.parse(chatflow.speechToText) @@ -99,6 +115,7 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter databaseEntities: databaseEntities } const speechToTextResult = await convertSpeechToText(upload, speechToTextConfig, options) + logger.debug(`Speech to text result: ${speechToTextResult}`) if (speechToTextResult) { incomingInput.question = speechToTextResult } @@ -109,20 +126,21 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter let isStreamValid = false - const files = (req.files as any[]) || [] + const files = (req.files as Express.Multer.File[]) || [] if (files.length) { const overrideConfig: ICommonObject = { ...req.body } + const fileNames: string[] = [] for (const file of files) { - const fileData = fs.readFileSync(file.path, { encoding: 'base64' }) - const dataBase64String = `data:${file.mimetype};base64,${fileData},filename:${file.filename}` + const fileBuffer = fs.readFileSync(file.path) + + const storagePath = await addArrayFilesToStorage(file.mimetype, fileBuffer, file.originalname, fileNames, chatflowid) const fileInputField = mapMimeTypeToInputField(file.mimetype) - if (overrideConfig[fileInputField]) { - overrideConfig[fileInputField] = JSON.stringify([...JSON.parse(overrideConfig[fileInputField]), dataBase64String]) - } else { - overrideConfig[fileInputField] = JSON.stringify([dataBase64String]) - } + + overrideConfig[fileInputField] = storagePath + + fs.unlinkSync(file.path) } incomingInput = { question: req.body.question ?? 'hello', @@ -137,17 +155,42 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter const nodes = parsedFlowData.nodes const edges = parsedFlowData.edges - // Get session ID + /*** Get session ID ***/ const memoryNode = findMemoryNode(nodes, edges) const memoryType = memoryNode?.data.label let sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal) + /*** Get Ending Node with Directed Graph ***/ + const { graph, nodeDependencies } = constructGraphs(nodes, edges) + const directedGraph = graph + const endingNodes = getEndingNodes(nodeDependencies, directedGraph, nodes) + + /*** If the graph is an agent graph, build the agent response ***/ + if (endingNodes.filter((node) => node.data.category === 'Multi Agents').length) { + return await utilBuildAgentResponse( + chatflow, + isInternal, + chatId, + memoryType ?? '', + sessionId, + userMessageDateTime, + fileUploads, + incomingInput, + nodes, + edges, + socketIO, + baseURL + ) + } + + // Get prepend messages + const prependMessages = incomingInput.history + /* Reuse the flow without having to rebuild (to avoid duplicated upsert, recomputation, reinitialization of memory) when all these conditions met: * - Node Data already exists in pool * - Still in sync (i.e the flow has not been modified since) * - Existing overrideConfig and new overrideConfig are the same * - Flow doesn't start with/contain nodes that depend on incomingInput.question - * TODO: convert overrideConfig to hash when we no longer store base64 string but filepath ***/ const isFlowReusable = () => { return ( @@ -170,13 +213,7 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter `[server]: Reuse existing chatflow ${chatflowid} with ending node ${nodeToExecuteData.label} (${nodeToExecuteData.id})` ) } else { - /*** Get Ending Node with Directed Graph ***/ - const { graph, nodeDependencies } = constructGraphs(nodes, edges) - const directedGraph = graph - - const endingNodes = getEndingNodes(nodeDependencies, directedGraph, nodes) - - let isCustomFunctionEndingNode = endingNodes.some((node) => node.data?.outputs?.output === 'EndingNode') + const isCustomFunctionEndingNode = endingNodes.some((node) => node.data?.outputs?.output === 'EndingNode') for (const endingNode of endingNodes) { const endingNodeData = endingNode.data @@ -223,7 +260,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter appServer.nodesPool.componentNodes, appServer.AppDataSource, databaseEntities, - logger + logger, + prependMessages ) } @@ -261,7 +299,10 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter appServer.cachePool, false, undefined, - incomingInput.uploads + incomingInput.uploads, + baseURL, + socketIO, + incomingInput.socketIOClientId ) const nodeToExecute = @@ -298,7 +339,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter analytic: chatflow.analytic, uploads: incomingInput.uploads, socketIO, - socketIOClientId: incomingInput.socketIOClientId + socketIOClientId: incomingInput.socketIOClientId, + prependMessages }) : await nodeInstance.run(nodeToExecuteData, incomingInput.question, { chatId, @@ -307,7 +349,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter appDataSource: appServer.AppDataSource, databaseEntities, analytic: chatflow.analytic, - uploads: incomingInput.uploads + uploads: incomingInput.uploads, + prependMessages }) result = typeof result === 'string' ? { text: result } : result @@ -363,13 +406,92 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter // this is used when input text is empty but question is in audio format result.question = incomingInput.question result.chatId = chatId - result.chatMessageId = chatMessage.id + result.chatMessageId = chatMessage?.id if (sessionId) result.sessionId = sessionId if (memoryType) result.memoryType = memoryType return result - } catch (e: any) { + } catch (e) { + logger.error('[server]: Error:', e) + throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, getErrorMessage(e)) + } +} + +const utilBuildAgentResponse = async ( + chatflow: IChatFlow, + isInternal: boolean, + chatId: string, + memoryType: string, + sessionId: string, + userMessageDateTime: Date, + fileUploads: IFileUpload[], + incomingInput: ICommonObject, + nodes: IReactFlowNode[], + edges: IReactFlowEdge[], + socketIO?: Server, + baseURL?: string +) => { + try { + const appServer = getRunningExpressApp() + const streamResults = await buildAgentGraph(chatflow, chatId, sessionId, incomingInput, baseURL, socketIO) + if (streamResults) { + const { finalResult, agentReasoning } = streamResults + const userMessage: Omit = { + role: 'userMessage', + content: incomingInput.question, + chatflowid: chatflow.id, + chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL, + chatId, + memoryType, + sessionId, + createdDate: userMessageDateTime, + fileUploads: incomingInput.uploads ? JSON.stringify(fileUploads) : undefined, + leadEmail: incomingInput.leadEmail + } + await utilAddChatMessage(userMessage) + + const apiMessage: Omit = { + role: 'apiMessage', + content: finalResult, + chatflowid: chatflow.id, + chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL, + chatId, + memoryType, + sessionId + } + if (agentReasoning.length) apiMessage.agentReasoning = JSON.stringify(agentReasoning) + const chatMessage = await utilAddChatMessage(apiMessage) + + await appServer.telemetry.sendTelemetry('prediction_sent', { + version: await getAppVersion(), + chatlowId: chatflow.id, + chatId, + type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL, + flowGraph: getTelemetryFlowObj(nodes, edges) + }) + + // Prepare response + let result: ICommonObject = {} + result.text = finalResult + result.question = incomingInput.question + result.chatId = chatId + result.chatMessageId = chatMessage?.id + if (sessionId) result.sessionId = sessionId + if (memoryType) result.memoryType = memoryType + if (agentReasoning.length) result.agentReasoning = agentReasoning + + await appServer.telemetry.sendTelemetry('graph_compiled', { + version: await getAppVersion(), + graphId: chatflow.id, + type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL, + flowGraph: getTelemetryFlowObj(nodes, edges) + }) + + return result + } + return undefined + } catch (e) { logger.error('[server]: Error:', e) - throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, e.message) + throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, getErrorMessage(e)) } } diff --git a/packages/server/src/utils/getUploadsConfig.ts b/packages/server/src/utils/getUploadsConfig.ts index 13d18eb9d64..d89e1848abc 100644 --- a/packages/server/src/utils/getUploadsConfig.ts +++ b/packages/server/src/utils/getUploadsConfig.ts @@ -18,7 +18,7 @@ export const utilGetUploadsConfig = async (chatflowid: string): Promise => throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${chatflowid} not found`) } - const uploadAllowedNodes = ['llmChain', 'conversationChain', 'reactAgentChat', 'conversationalAgent', 'toolAgent'] + const uploadAllowedNodes = ['llmChain', 'conversationChain', 'reactAgentChat', 'conversationalAgent', 'toolAgent', 'supervisor'] const uploadProcessingNodes = ['chatOpenAI', 'chatAnthropic', 'awsChatBedrock', 'azureChatOpenAI', 'chatGoogleGenerativeAI'] const flowObj = JSON.parse(chatflow.flowData) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index e176fd622dd..1b5d9ed6dda 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -1,6 +1,7 @@ import path from 'path' import fs from 'fs' import logger from './logger' +import { Server } from 'socket.io' import { IComponentCredentials, IComponentNodes, @@ -267,9 +268,10 @@ export const getEndingNodes = ( endingNodeData && endingNodeData.category !== 'Chains' && endingNodeData.category !== 'Agents' && - endingNodeData.category !== 'Engine' + endingNodeData.category !== 'Engine' && + endingNodeData.category !== 'Multi Agents' ) { - error = new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Ending node must be either a Chain or Agent`) + error = new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Ending node must be either a Chain or Agent or Engine`) continue } } @@ -374,6 +376,44 @@ export const saveUpsertFlowData = (nodeData: INodeData, upsertHistory: Record { + let outputId = '' + + if (reactFlowNode.data.outputAnchors.length) { + if (Object.keys(reactFlowNode.data.outputs || {}).length) { + const output = reactFlowNode.data.outputs?.output + const node = reactFlowNode.data.outputAnchors[0].options?.find((anchor) => anchor.name === output) + if (node) outputId = (node as ICommonObject).id + } else { + outputId = (reactFlowNode.data.outputAnchors[0] as ICommonObject).id + } + } + + const targetNodeId = reactFlowEdges.find((edge) => edge.sourceHandle === outputId)?.target + + if (targetNodeId) { + const targetNodeCategory = reactFlowNodes.find((nd) => nd.id === targetNodeId)?.data.category || '' + if (targetNodeCategory === 'Vector Stores') { + return true + } + } + + return false +} + /** * Build langchain from start to end * @param {string[]} startingNodeIds @@ -405,7 +445,10 @@ export const buildFlow = async ( cachePool?: CachePool, isUpsert?: boolean, stopNodeId?: string, - uploads?: IFileUpload[] + uploads?: IFileUpload[], + baseURL?: string, + socketIO?: Server, + socketIOClientId?: string ) => { const flowNodes = cloneDeep(reactFlowNodes) @@ -446,7 +489,6 @@ export const buildFlow = async ( const reactFlowNodeData: INodeData = resolveVariables(flowNodeData, flowNodes, question, chatHistory) - // TODO: Avoid processing Text Splitter + Doc Loader once Upsert & Load Existing Vector Nodes are deprecated if (isUpsert && stopNodeId && nodeId === stopNodeId) { logger.debug(`[server]: Upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) const indexResult = await newNodeInstance.vectorStoreMethods!['upsert']!.call(newNodeInstance, reactFlowNodeData, { @@ -459,11 +501,20 @@ export const buildFlow = async ( databaseEntities, cachePool, dynamicVariables, - uploads + uploads, + baseURL, + socketIO, + socketIOClientId }) if (indexResult) upsertHistory['result'] = indexResult logger.debug(`[server]: Finished upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) break + } else if ( + !isUpsert && + reactFlowNode.data.category === 'Document Loaders' && + checkIfDocLoaderShouldBeIgnored(reactFlowNode, reactFlowNodes, reactFlowEdges) + ) { + initializedNodes.add(nodeId) } else { logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) let outputResult = await newNodeInstance.init(reactFlowNodeData, question, { @@ -477,7 +528,10 @@ export const buildFlow = async ( cachePool, isUpsert, dynamicVariables, - uploads + uploads, + baseURL, + socketIO, + socketIOClientId }) // Save dynamic variables @@ -935,7 +989,7 @@ export const mapMimeTypeToInputField = (mimeType: string) => { case 'text/yaml': return 'yamlFile' default: - return '' + return 'txtFile' } } @@ -1005,7 +1059,6 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component } } } - return configs } @@ -1263,7 +1316,8 @@ export const getSessionChatHistory = async ( componentNodes: IComponentNodes, appDataSource: DataSource, databaseEntities: IDatabaseEntity, - logger: any + logger: any, + prependMessages?: IMessage[] ): Promise => { const nodeInstanceFilePath = componentNodes[memoryNode.data.name].filePath as string const nodeModule = await import(nodeInstanceFilePath) @@ -1281,7 +1335,7 @@ export const getSessionChatHistory = async ( logger }) - return (await initializedInstance.getChatMessages(sessionId)) as IMessage[] + return (await initializedInstance.getChatMessages(sessionId, undefined, prependMessages)) as IMessage[] } /** diff --git a/packages/server/src/utils/upsertVector.ts b/packages/server/src/utils/upsertVector.ts index 73c6e3fb5cf..175b71683c5 100644 --- a/packages/server/src/utils/upsertVector.ts +++ b/packages/server/src/utils/upsertVector.ts @@ -1,7 +1,7 @@ import { Request } from 'express' import * as fs from 'fs' import { cloneDeep, omit } from 'lodash' -import { ICommonObject, IMessage } from 'flowise-components' +import { ICommonObject, IMessage, addArrayFilesToStorage } from 'flowise-components' import telemetryService from '../services/telemetry' import logger from '../utils/logger' import { @@ -48,20 +48,21 @@ export const upsertVector = async (req: Request, isInternal: boolean = false) => } } - const files = (req.files as any[]) || [] + const files = (req.files as Express.Multer.File[]) || [] if (files.length) { const overrideConfig: ICommonObject = { ...req.body } + const fileNames: string[] = [] for (const file of files) { - const fileData = fs.readFileSync(file.path, { encoding: 'base64' }) - const dataBase64String = `data:${file.mimetype};base64,${fileData},filename:${file.filename}` + const fileBuffer = fs.readFileSync(file.path) + + const storagePath = await addArrayFilesToStorage(file.mimetype, fileBuffer, file.originalname, fileNames, chatflowid) const fileInputField = mapMimeTypeToInputField(file.mimetype) - if (overrideConfig[fileInputField]) { - overrideConfig[fileInputField] = JSON.stringify([...JSON.parse(overrideConfig[fileInputField]), dataBase64String]) - } else { - overrideConfig[fileInputField] = JSON.stringify([dataBase64String]) - } + + overrideConfig[fileInputField] = storagePath + + fs.unlinkSync(file.path) } incomingInput = { question: req.body.question ?? 'hello', diff --git a/packages/ui/package.json b/packages/ui/package.json index 4c3f3d0e4b4..3eb1776ef7a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "flowise-ui", - "version": "1.7.1", + "version": "1.7.2", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://flowiseai.com", "author": { @@ -18,7 +18,7 @@ "@mui/lab": "5.0.0-alpha.156", "@mui/material": "5.15.0", "@mui/x-data-grid": "6.8.0", - "@tabler/icons": "^1.39.1", + "@tabler/icons-react": "^3.3.0", "@uiw/codemirror-theme-sublime": "^4.21.21", "@uiw/codemirror-theme-vscode": "^4.21.21", "@uiw/react-codemirror": "^4.21.21", diff --git a/packages/ui/src/ErrorBoundary.jsx b/packages/ui/src/ErrorBoundary.jsx index 63636973ede..bbe4fafe3b1 100644 --- a/packages/ui/src/ErrorBoundary.jsx +++ b/packages/ui/src/ErrorBoundary.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types' import { Box, Card, IconButton, Stack, Typography, useTheme } from '@mui/material' -import { IconCopy } from '@tabler/icons' +import { IconCopy } from '@tabler/icons-react' const ErrorBoundary = ({ error }) => { const theme = useTheme() diff --git a/packages/ui/src/api/chatflows.js b/packages/ui/src/api/chatflows.js index 586fe183a60..aa305d14fbb 100644 --- a/packages/ui/src/api/chatflows.js +++ b/packages/ui/src/api/chatflows.js @@ -2,6 +2,8 @@ import client from './client' const getAllChatflows = () => client.get('/chatflows') +const getAllAgentflows = () => client.get('/chatflows?type=MULTIAGENT') + const getSpecificChatflow = (id) => client.get(`/chatflows/${id}`) const getSpecificChatflowFromPublicEndpoint = (id) => client.get(`/public-chatflows/${id}`) @@ -18,6 +20,7 @@ const getAllowChatflowUploads = (id) => client.get(`/chatflows-uploads/${id}`) export default { getAllChatflows, + getAllAgentflows, getSpecificChatflow, getSpecificChatflowFromPublicEndpoint, createNewChatflow, diff --git a/packages/ui/src/api/chatmessage.js b/packages/ui/src/api/chatmessage.js index 8760ce077e9..aa8edfc88b8 100644 --- a/packages/ui/src/api/chatmessage.js +++ b/packages/ui/src/api/chatmessage.js @@ -7,11 +7,13 @@ const getAllChatmessageFromChatflow = (id, params = {}) => const getChatmessageFromPK = (id, params = {}) => client.get(`/chatmessage/${id}`, { params: { order: 'ASC', feedback: true, ...params } }) const deleteChatmessage = (id, params = {}) => client.delete(`/chatmessage/${id}`, { params: { ...params } }) const getStoragePath = () => client.get(`/get-upload-path`) +const abortMessage = (chatflowid, chatid) => client.put(`/chatmessage/abort/${chatflowid}/${chatid}`) export default { getInternalChatmessageFromChatflow, getAllChatmessageFromChatflow, getChatmessageFromPK, deleteChatmessage, - getStoragePath + getStoragePath, + abortMessage } diff --git a/packages/ui/src/assets/images/agentgraph.png b/packages/ui/src/assets/images/agentgraph.png new file mode 100644 index 00000000000..384dec203fa Binary files /dev/null and b/packages/ui/src/assets/images/agentgraph.png differ diff --git a/packages/ui/src/assets/images/agents_empty.svg b/packages/ui/src/assets/images/agents_empty.svg new file mode 100644 index 00000000000..8fbf0881258 --- /dev/null +++ b/packages/ui/src/assets/images/agents_empty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/ui/src/assets/images/assistant_empty.svg b/packages/ui/src/assets/images/assistant_empty.svg new file mode 100644 index 00000000000..cc9cda37b6d --- /dev/null +++ b/packages/ui/src/assets/images/assistant_empty.svg @@ -0,0 +1 @@ +server down \ No newline at end of file diff --git a/packages/ui/src/assets/images/localai.png b/packages/ui/src/assets/images/localai.png new file mode 100644 index 00000000000..321403973da Binary files /dev/null and b/packages/ui/src/assets/images/localai.png differ diff --git a/packages/ui/src/assets/images/multiagent_supervisor.png b/packages/ui/src/assets/images/multiagent_supervisor.png new file mode 100644 index 00000000000..3c11bb9f0fc Binary files /dev/null and b/packages/ui/src/assets/images/multiagent_supervisor.png differ diff --git a/packages/ui/src/assets/images/multiagent_worker.png b/packages/ui/src/assets/images/multiagent_worker.png new file mode 100644 index 00000000000..3b6e812ee8c Binary files /dev/null and b/packages/ui/src/assets/images/multiagent_worker.png differ diff --git a/packages/ui/src/assets/images/next-agent.gif b/packages/ui/src/assets/images/next-agent.gif new file mode 100644 index 00000000000..956c129d1c7 Binary files /dev/null and b/packages/ui/src/assets/images/next-agent.gif differ diff --git a/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.jsx b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.jsx index 39f9a8e0bf6..da8d2e1af75 100644 --- a/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.jsx +++ b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.jsx @@ -28,7 +28,7 @@ import Transitions from '@/ui-component/extended/Transitions' import AboutDialog from '@/ui-component/dialog/AboutDialog' // assets -import { IconLogout, IconSettings, IconInfoCircle } from '@tabler/icons' +import { IconLogout, IconSettings, IconInfoCircle } from '@tabler/icons-react' import './index.css' diff --git a/packages/ui/src/layout/MainLayout/Header/index.jsx b/packages/ui/src/layout/MainLayout/Header/index.jsx index 8549d2c5d28..53d6402bdf2 100644 --- a/packages/ui/src/layout/MainLayout/Header/index.jsx +++ b/packages/ui/src/layout/MainLayout/Header/index.jsx @@ -13,7 +13,7 @@ import LogoSection from '../LogoSection' import ProfileSection from './ProfileSection' // assets -import { IconMenu2 } from '@tabler/icons' +import { IconMenu2 } from '@tabler/icons-react' // store import { SET_DARKMODE } from '@/store/actions' diff --git a/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavCollapse/index.jsx b/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavCollapse/index.jsx index 4fb11edf51a..b54d1c4a5fc 100644 --- a/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavCollapse/index.jsx +++ b/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavCollapse/index.jsx @@ -11,7 +11,7 @@ import NavItem from '../NavItem' // assets import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord' -import { IconChevronDown, IconChevronUp } from '@tabler/icons' +import { IconChevronDown, IconChevronUp } from '@tabler/icons-react' // ==============================|| SIDEBAR MENU LIST COLLAPSE ITEMS ||============================== // diff --git a/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavItem/index.jsx b/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavItem/index.jsx index d4d409178a9..f9a2959b975 100644 --- a/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavItem/index.jsx +++ b/packages/ui/src/layout/MainLayout/Sidebar/MenuList/NavItem/index.jsx @@ -135,6 +135,18 @@ const NavItem = ({ item, level, navType, onClick, onUploadFile }) => { avatar={item.chip.avatar && {item.chip.avatar}} /> )} + {item.isBeta && ( + + )} ) } diff --git a/packages/ui/src/layout/MainLayout/ViewHeader.jsx b/packages/ui/src/layout/MainLayout/ViewHeader.jsx index 9541b016971..29eddbb4ae3 100644 --- a/packages/ui/src/layout/MainLayout/ViewHeader.jsx +++ b/packages/ui/src/layout/MainLayout/ViewHeader.jsx @@ -6,7 +6,7 @@ import { useTheme } from '@mui/material/styles' import { StyledFab } from '@/ui-component/button/StyledFab' // icons -import { IconSearch, IconArrowLeft, IconEdit } from '@tabler/icons' +import { IconSearch, IconArrowLeft, IconEdit } from '@tabler/icons-react' const ViewHeader = ({ children, diff --git a/packages/ui/src/menu-items/agentsettings.js b/packages/ui/src/menu-items/agentsettings.js new file mode 100644 index 00000000000..0fef22254e1 --- /dev/null +++ b/packages/ui/src/menu-items/agentsettings.js @@ -0,0 +1,84 @@ +// assets +import { + IconTrash, + IconFileUpload, + IconFileExport, + IconCopy, + IconMessage, + IconDatabaseExport, + IconAdjustmentsHorizontal, + IconUsers +} from '@tabler/icons-react' + +// constant +const icons = { + IconTrash, + IconFileUpload, + IconFileExport, + IconCopy, + IconMessage, + IconDatabaseExport, + IconAdjustmentsHorizontal, + IconUsers +} + +// ==============================|| SETTINGS MENU ITEMS ||============================== // + +const agent_settings = { + id: 'settings', + title: '', + type: 'group', + children: [ + { + id: 'viewMessages', + title: 'View Messages', + type: 'item', + url: '', + icon: icons.IconMessage + }, + { + id: 'viewLeads', + title: 'View Leads', + type: 'item', + url: '', + icon: icons.IconUsers + }, + { + id: 'chatflowConfiguration', + title: 'Configuration', + type: 'item', + url: '', + icon: icons.IconAdjustmentsHorizontal + }, + { + id: 'duplicateChatflow', + title: 'Duplicate Agents', + type: 'item', + url: '', + icon: icons.IconCopy + }, + { + id: 'loadChatflow', + title: 'Load Agents', + type: 'item', + url: '', + icon: icons.IconFileUpload + }, + { + id: 'exportChatflow', + title: 'Export Agents', + type: 'item', + url: '', + icon: icons.IconFileExport + }, + { + id: 'deleteChatflow', + title: 'Delete Agents', + type: 'item', + url: '', + icon: icons.IconTrash + } + ] +} + +export default agent_settings diff --git a/packages/ui/src/menu-items/dashboard.js b/packages/ui/src/menu-items/dashboard.js index b9c83a0c19e..95992e9648a 100644 --- a/packages/ui/src/menu-items/dashboard.js +++ b/packages/ui/src/menu-items/dashboard.js @@ -1,8 +1,18 @@ // assets -import { IconHierarchy, IconBuildingStore, IconKey, IconTool, IconLock, IconRobot, IconVariable, IconFiles } from '@tabler/icons' +import { + IconUsersGroup, + IconHierarchy, + IconBuildingStore, + IconKey, + IconTool, + IconLock, + IconRobot, + IconVariable, + IconFiles +} from '@tabler/icons-react' // constant -const icons = { IconHierarchy, IconBuildingStore, IconKey, IconTool, IconLock, IconRobot, IconVariable, IconFiles } +const icons = { IconUsersGroup, IconHierarchy, IconBuildingStore, IconKey, IconTool, IconLock, IconRobot, IconVariable, IconFiles } // ==============================|| DASHBOARD MENU ITEMS ||============================== // @@ -19,6 +29,15 @@ const dashboard = { icon: icons.IconHierarchy, breadcrumbs: true }, + { + id: 'agentflows', + title: 'Agentflows', + type: 'item', + url: '/agentflows', + icon: icons.IconUsersGroup, + breadcrumbs: true, + isBeta: true + }, { id: 'marketplaces', title: 'Marketplaces', @@ -68,7 +87,7 @@ const dashboard = { breadcrumbs: true }, { - id: 'documents', + id: 'document-stores', title: 'Document Stores', type: 'item', url: '/document-stores', diff --git a/packages/ui/src/menu-items/settings.js b/packages/ui/src/menu-items/settings.js index fecda1ee8d5..6b8d8bc73ab 100644 --- a/packages/ui/src/menu-items/settings.js +++ b/packages/ui/src/menu-items/settings.js @@ -8,7 +8,7 @@ import { IconDatabaseExport, IconAdjustmentsHorizontal, IconUsers -} from '@tabler/icons' +} from '@tabler/icons-react' // constant const icons = { diff --git a/packages/ui/src/routes/CanvasRoutes.jsx b/packages/ui/src/routes/CanvasRoutes.jsx index f0ea1eb32b1..0a278c0f6b5 100644 --- a/packages/ui/src/routes/CanvasRoutes.jsx +++ b/packages/ui/src/routes/CanvasRoutes.jsx @@ -22,6 +22,14 @@ const CanvasRoutes = { path: '/canvas/:id', element: }, + { + path: '/agentcanvas', + element: + }, + { + path: '/agentcanvas/:id', + element: + }, { path: '/marketplace/:id', element: diff --git a/packages/ui/src/routes/MainRoutes.jsx b/packages/ui/src/routes/MainRoutes.jsx index 9b2db96417a..76783dc0135 100644 --- a/packages/ui/src/routes/MainRoutes.jsx +++ b/packages/ui/src/routes/MainRoutes.jsx @@ -7,6 +7,9 @@ import Loadable from '@/ui-component/loading/Loadable' // chatflows routing const Chatflows = Loadable(lazy(() => import('@/views/chatflows'))) +// agents routing +const Agentflows = Loadable(lazy(() => import('@/views/agentflows'))) + // marketplaces routing const Marketplaces = Loadable(lazy(() => import('@/views/marketplaces'))) @@ -45,6 +48,10 @@ const MainRoutes = { path: '/chatflows', element: }, + { + path: '/agentflows', + element: + }, { path: '/marketplaces', element: diff --git a/packages/ui/src/ui-component/button/CopyToClipboardButton.jsx b/packages/ui/src/ui-component/button/CopyToClipboardButton.jsx index ee9cc752474..916b2ab989a 100644 --- a/packages/ui/src/ui-component/button/CopyToClipboardButton.jsx +++ b/packages/ui/src/ui-component/button/CopyToClipboardButton.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types' import { useSelector } from 'react-redux' import { IconButton } from '@mui/material' -import { IconClipboard } from '@tabler/icons' +import { IconClipboard } from '@tabler/icons-react' const CopyToClipboardButton = (props) => { const customization = useSelector((state) => state.customization) diff --git a/packages/ui/src/ui-component/button/FlowListMenu.jsx b/packages/ui/src/ui-component/button/FlowListMenu.jsx index 9c247b2365a..07c44104827 100644 --- a/packages/ui/src/ui-component/button/FlowListMenu.jsx +++ b/packages/ui/src/ui-component/button/FlowListMenu.jsx @@ -17,7 +17,7 @@ import VpnLockOutlinedIcon from '@mui/icons-material/VpnLockOutlined' import MicNoneOutlinedIcon from '@mui/icons-material/MicNoneOutlined' import Button from '@mui/material/Button' import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' -import { IconX } from '@tabler/icons' +import { IconX } from '@tabler/icons-react' import chatflowsApi from '@/api/chatflows' @@ -72,7 +72,7 @@ const StyledMenu = styled((props) => ( } })) -export default function FlowListMenu({ chatflow, setError, updateFlowsApi }) { +export default function FlowListMenu({ chatflow, isAgentCanvas, setError, updateFlowsApi }) { const { confirm } = useConfirm() const dispatch = useDispatch() const updateChatflowApi = useApi(chatflowsApi.updateChatflow) @@ -95,6 +95,8 @@ export default function FlowListMenu({ chatflow, setError, updateFlowsApi }) { const [speechToTextDialogOpen, setSpeechToTextDialogOpen] = useState(false) const [speechToTextDialogProps, setSpeechToTextDialogProps] = useState({}) + const title = isAgentCanvas ? 'Agents' : 'Chatflow' + const handleClick = (event) => { setAnchorEl(event.currentTarget) } @@ -213,7 +215,7 @@ export default function FlowListMenu({ chatflow, setError, updateFlowsApi }) { setAnchorEl(null) const confirmPayload = { title: `Delete`, - description: `Delete chatflow ${chatflow.name}?`, + description: `Delete ${title} ${chatflow.name}?`, confirmButtonName: 'Delete', cancelButtonName: 'Cancel' } @@ -246,7 +248,7 @@ export default function FlowListMenu({ chatflow, setError, updateFlowsApi }) { setAnchorEl(null) try { localStorage.setItem('duplicatedFlowData', chatflow.flowData) - window.open(`${uiBaseURL}/canvas`, '_blank') + window.open(`${uiBaseURL}/${isAgentCanvas ? 'agentcanvas' : 'canvas'}`, '_blank') } catch (e) { console.error(e) } @@ -259,7 +261,7 @@ export default function FlowListMenu({ chatflow, setError, updateFlowsApi }) { let dataStr = JSON.stringify(generateExportFlowData(flowData), null, 2) let dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr) - let exportFileDefaultName = `${chatflow.name} Chatflow.json` + let exportFileDefaultName = `${chatflow.name} ${title}.json` let linkElement = document.createElement('a') linkElement.setAttribute('href', dataUri) @@ -334,7 +336,7 @@ export default function FlowListMenu({ chatflow, setError, updateFlowsApi }) { { const customization = useSelector((state) => state.customization) diff --git a/packages/ui/src/ui-component/button/ThumbsUpButton.jsx b/packages/ui/src/ui-component/button/ThumbsUpButton.jsx index c1b5106e9a5..e41a9544225 100644 --- a/packages/ui/src/ui-component/button/ThumbsUpButton.jsx +++ b/packages/ui/src/ui-component/button/ThumbsUpButton.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types' import { useSelector } from 'react-redux' import { IconButton } from '@mui/material' -import { IconThumbUp } from '@tabler/icons' +import { IconThumbUp } from '@tabler/icons-react' const ThumbsUpButton = (props) => { const customization = useSelector((state) => state.customization) diff --git a/packages/ui/src/ui-component/cards/DocumentStoreCard.jsx b/packages/ui/src/ui-component/cards/DocumentStoreCard.jsx index 71442f80769..da2c2d4ad33 100644 --- a/packages/ui/src/ui-component/cards/DocumentStoreCard.jsx +++ b/packages/ui/src/ui-component/cards/DocumentStoreCard.jsx @@ -4,7 +4,7 @@ import { useSelector } from 'react-redux' // material-ui import { styled } from '@mui/material/styles' import { Box, Grid, Typography, useTheme } from '@mui/material' -import { IconVectorBezier2, IconLanguage, IconScissors } from '@tabler/icons' +import { IconVectorBezier2, IconLanguage, IconScissors } from '@tabler/icons-react' // project imports import MainCard from '@/ui-component/cards/MainCard' diff --git a/packages/ui/src/ui-component/dialog/ManageScrapedLinksDialog.jsx b/packages/ui/src/ui-component/dialog/ManageScrapedLinksDialog.jsx index b44fae7d15f..788c1998a82 100644 --- a/packages/ui/src/ui-component/dialog/ManageScrapedLinksDialog.jsx +++ b/packages/ui/src/ui-component/dialog/ManageScrapedLinksDialog.jsx @@ -16,7 +16,7 @@ import { Stack, Typography } from '@mui/material' -import { IconEraser, IconTrash, IconX } from '@tabler/icons' +import { IconEraser, IconTrash, IconX } from '@tabler/icons-react' import PerfectScrollbar from 'react-perfect-scrollbar' import { BackdropLoader } from '@/ui-component/loading/BackdropLoader' diff --git a/packages/ui/src/ui-component/dialog/ViewLeadsDialog.jsx b/packages/ui/src/ui-component/dialog/ViewLeadsDialog.jsx index 42c9ade3a1c..53de3f0f543 100644 --- a/packages/ui/src/ui-component/dialog/ViewLeadsDialog.jsx +++ b/packages/ui/src/ui-component/dialog/ViewLeadsDialog.jsx @@ -23,7 +23,7 @@ import { OutlinedInput } from '@mui/material' import { useTheme } from '@mui/material/styles' -import { IconFileExport, IconSearch } from '@tabler/icons' +import { IconFileExport, IconSearch } from '@tabler/icons-react' import leadsEmptySVG from '@/assets/images/leads_empty.svg' // store diff --git a/packages/ui/src/ui-component/dialog/ViewMessagesDialog.jsx b/packages/ui/src/ui-component/dialog/ViewMessagesDialog.jsx index dd2858f2086..ed735be070c 100644 --- a/packages/ui/src/ui-component/dialog/ViewMessagesDialog.jsx +++ b/packages/ui/src/ui-component/dialog/ViewMessagesDialog.jsx @@ -23,7 +23,8 @@ import { ListItemText, Chip, Card, - CardMedia + CardMedia, + CardContent } from '@mui/material' import { useTheme } from '@mui/material/styles' import DatePicker from 'react-datepicker' @@ -31,7 +32,9 @@ import DatePicker from 'react-datepicker' import robotPNG from '@/assets/images/robot.png' import userPNG from '@/assets/images/account.png' import msgEmptySVG from '@/assets/images/message_empty.svg' -import { IconFileExport, IconEraser, IconX, IconDownload } from '@tabler/icons' +import multiagent_supervisorPNG from '@/assets/images/multiagent_supervisor.png' +import multiagent_workerPNG from '@/assets/images/multiagent_worker.png' +import { IconFileExport, IconEraser, IconX, IconDownload } from '@tabler/icons-react' // Project import import { MemoizedReactMarkdown } from '@/ui-component/markdown/MemoizedReactMarkdown' @@ -185,6 +188,7 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { if (chatmsg.usedTools) msg.usedTools = JSON.parse(chatmsg.usedTools) if (chatmsg.fileAnnotations) msg.fileAnnotations = JSON.parse(chatmsg.fileAnnotations) if (chatmsg.feedback) msg.feedback = chatmsg.feedback?.content + if (chatmsg.agentReasoning) msg.agentReasoning = JSON.parse(chatmsg.agentReasoning) if (!Object.prototype.hasOwnProperty.call(obj, chatPK)) { obj[chatPK] = { @@ -319,6 +323,7 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { if (chatmsg.sourceDocuments) obj.sourceDocuments = JSON.parse(chatmsg.sourceDocuments) if (chatmsg.usedTools) obj.usedTools = JSON.parse(chatmsg.usedTools) if (chatmsg.fileAnnotations) obj.fileAnnotations = JSON.parse(chatmsg.fileAnnotations) + if (chatmsg.agentReasoning) obj.agentReasoning = JSON.parse(chatmsg.agentReasoning) loadedMessages.push(obj) } @@ -803,6 +808,97 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => { })} )} + {message.agentReasoning && ( +
+ {message.agentReasoning.map((agent, index) => { + return ( + + + + + agentPNG + +
{agent.agentName}
+
+ {agent.messages.length > 0 && ( + + ) : ( + + {children} + + ) + } + }} + > + {agent.messages.length > 1 + ? agent.messages.join('\\n') + : agent.messages[0]} + + )} + {agent.instructions &&

{agent.instructions}

} + {agent.messages.length === 0 && + !agent.instructions &&

Finished

} +
+
+ ) + })} +
+ )}
{/* Messages are being rendered in Markdown format */} { diff --git a/packages/ui/src/ui-component/extended/StarterPrompts.jsx b/packages/ui/src/ui-component/extended/StarterPrompts.jsx index 89a40642be5..8ed2baf55a2 100644 --- a/packages/ui/src/ui-component/extended/StarterPrompts.jsx +++ b/packages/ui/src/ui-component/extended/StarterPrompts.jsx @@ -5,7 +5,7 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba // material-ui import { Button, IconButton, OutlinedInput, Box, List, InputAdornment } from '@mui/material' -import { IconX, IconTrash, IconPlus, IconBulb } from '@tabler/icons' +import { IconX, IconTrash, IconPlus, IconBulb } from '@tabler/icons-react' // Project import import { StyledButton } from '@/ui-component/button/StyledButton' diff --git a/packages/ui/src/ui-component/file/File.jsx b/packages/ui/src/ui-component/file/File.jsx index 874fd842eff..0c81a79fdd3 100644 --- a/packages/ui/src/ui-component/file/File.jsx +++ b/packages/ui/src/ui-component/file/File.jsx @@ -2,7 +2,7 @@ import { useState } from 'react' import PropTypes from 'prop-types' import { useTheme } from '@mui/material/styles' import { FormControl, Button } from '@mui/material' -import { IconUpload } from '@tabler/icons' +import { IconUpload } from '@tabler/icons-react' import { getFileName } from '@/utils/genericHelper' export const File = ({ value, formDataUpload, fileType, onChange, onFormDataChange, disabled = false }) => { diff --git a/packages/ui/src/ui-component/grid/DataGrid.jsx b/packages/ui/src/ui-component/grid/DataGrid.jsx index 6f60c458ccd..a3f403a355f 100644 --- a/packages/ui/src/ui-component/grid/DataGrid.jsx +++ b/packages/ui/src/ui-component/grid/DataGrid.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types' import { useState, useCallback } from 'react' import { DataGrid as MUIDataGrid, GridActionsCellItem } from '@mui/x-data-grid' -import { IconPlus } from '@tabler/icons' +import { IconPlus } from '@tabler/icons-react' import { Button } from '@mui/material' import DeleteIcon from '@mui/icons-material/Delete' import { cloneDeep } from 'lodash' diff --git a/packages/ui/src/ui-component/markdown/CodeBlock.jsx b/packages/ui/src/ui-component/markdown/CodeBlock.jsx index 77caa346cd5..e6c50380724 100644 --- a/packages/ui/src/ui-component/markdown/CodeBlock.jsx +++ b/packages/ui/src/ui-component/markdown/CodeBlock.jsx @@ -1,4 +1,4 @@ -import { IconClipboard, IconDownload } from '@tabler/icons' +import { IconClipboard, IconDownload } from '@tabler/icons-react' import { memo, useState } from 'react' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism' diff --git a/packages/ui/src/ui-component/table/FlowListTable.jsx b/packages/ui/src/ui-component/table/FlowListTable.jsx index 88efa43ed19..48e2da12e3e 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.jsx +++ b/packages/ui/src/ui-component/table/FlowListTable.jsx @@ -41,7 +41,7 @@ const StyledTableRow = styled(TableRow)(() => ({ } })) -export const FlowListTable = ({ data, images, isLoading, filterFunction, updateFlowsApi, setError }) => { +export const FlowListTable = ({ data, images, isLoading, filterFunction, updateFlowsApi, setError, isAgentCanvas }) => { const theme = useTheme() const customization = useSelector((state) => state.customization) @@ -128,7 +128,10 @@ export const FlowListTable = ({ data, images, isLoading, filterFunction, updateF overflow: 'hidden' }} > - + {row.templateName || row.name} @@ -211,7 +214,12 @@ export const FlowListTable = ({ data, images, isLoading, filterFunction, updateF justifyContent='center' alignItems='center' > - + @@ -231,5 +239,6 @@ FlowListTable.propTypes = { isLoading: PropTypes.bool, filterFunction: PropTypes.func, updateFlowsApi: PropTypes.object, - setError: PropTypes.func + setError: PropTypes.func, + isAgentCanvas: PropTypes.bool } diff --git a/packages/ui/src/utils/genericHelper.js b/packages/ui/src/utils/genericHelper.js index f474a281afe..d57a550c0ab 100644 --- a/packages/ui/src/utils/genericHelper.js +++ b/packages/ui/src/utils/genericHelper.js @@ -549,14 +549,14 @@ export const removeDuplicateURL = (message) => { if (!message.sourceDocuments) return newSourceDocuments message.sourceDocuments.forEach((source) => { - if (source.metadata && source.metadata.source) { + if (source && source.metadata && source.metadata.source) { if (isValidURL(source.metadata.source) && !visitedURLs.includes(source.metadata.source)) { visitedURLs.push(source.metadata.source) newSourceDocuments.push(source) } else if (!isValidURL(source.metadata.source)) { newSourceDocuments.push(source) } - } else { + } else if (source) { newSourceDocuments.push(source) } }) diff --git a/packages/ui/src/views/agentflows/index.jsx b/packages/ui/src/views/agentflows/index.jsx new file mode 100644 index 00000000000..2d9572e0437 --- /dev/null +++ b/packages/ui/src/views/agentflows/index.jsx @@ -0,0 +1,218 @@ +import { useEffect, useState } from 'react' +import { useNavigate } from 'react-router-dom' + +// material-ui +import { Box, Skeleton, Stack, ToggleButton, ToggleButtonGroup } from '@mui/material' +import { useTheme } from '@mui/material/styles' + +// project imports +import MainCard from '@/ui-component/cards/MainCard' +import ItemCard from '@/ui-component/cards/ItemCard' +import { gridSpacing } from '@/store/constant' +import AgentsEmptySVG from '@/assets/images/agents_empty.svg' +import LoginDialog from '@/ui-component/dialog/LoginDialog' +import ConfirmDialog from '@/ui-component/dialog/ConfirmDialog' +import { FlowListTable } from '@/ui-component/table/FlowListTable' +import { StyledButton } from '@/ui-component/button/StyledButton' +import ViewHeader from '@/layout/MainLayout/ViewHeader' +import ErrorBoundary from '@/ErrorBoundary' + +// API +import chatflowsApi from '@/api/chatflows' + +// Hooks +import useApi from '@/hooks/useApi' + +// const +import { baseURL } from '@/store/constant' + +// icons +import { IconPlus, IconLayoutGrid, IconList } from '@tabler/icons-react' + +// ==============================|| AGENTS ||============================== // + +const Agentflows = () => { + const navigate = useNavigate() + const theme = useTheme() + + const [isLoading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [images, setImages] = useState({}) + const [search, setSearch] = useState('') + const [loginDialogOpen, setLoginDialogOpen] = useState(false) + const [loginDialogProps, setLoginDialogProps] = useState({}) + + const getAllAgentflows = useApi(chatflowsApi.getAllAgentflows) + const [view, setView] = useState(localStorage.getItem('flowDisplayStyle') || 'card') + + const handleChange = (event, nextView) => { + if (nextView === null) return + localStorage.setItem('flowDisplayStyle', nextView) + setView(nextView) + } + + const onSearchChange = (event) => { + setSearch(event.target.value) + } + + function filterFlows(data) { + return ( + data.name.toLowerCase().indexOf(search.toLowerCase()) > -1 || + (data.category && data.category.toLowerCase().indexOf(search.toLowerCase()) > -1) + ) + } + + const onLoginClick = (username, password) => { + localStorage.setItem('username', username) + localStorage.setItem('password', password) + navigate(0) + } + + const addNew = () => { + navigate('/agentcanvas') + } + + const goToCanvas = (selectedAgentflow) => { + navigate(`/agentcanvas/${selectedAgentflow.id}`) + } + + useEffect(() => { + getAllAgentflows.request() + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + useEffect(() => { + if (getAllAgentflows.error) { + if (getAllAgentflows.error?.response?.status === 401) { + setLoginDialogProps({ + title: 'Login', + confirmButtonName: 'Login' + }) + setLoginDialogOpen(true) + } else { + setError(getAllAgentflows.error) + } + } + }, [getAllAgentflows.error]) + + useEffect(() => { + setLoading(getAllAgentflows.loading) + }, [getAllAgentflows.loading]) + + useEffect(() => { + if (getAllAgentflows.data) { + try { + const agentflows = getAllAgentflows.data + const images = {} + for (let i = 0; i < agentflows.length; i += 1) { + const flowDataStr = agentflows[i].flowData + const flowData = JSON.parse(flowDataStr) + const nodes = flowData.nodes || [] + images[agentflows[i].id] = [] + for (let j = 0; j < nodes.length; j += 1) { + const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}` + if (!images[agentflows[i].id].includes(imageSrc)) { + images[agentflows[i].id].push(imageSrc) + } + } + } + setImages(images) + } catch (e) { + console.error(e) + } + } + }, [getAllAgentflows.data]) + + return ( + + {error ? ( + + ) : ( + + + + + + + + + + + } sx={{ borderRadius: 2, height: 40 }}> + Add New + + + {!view || view === 'card' ? ( + <> + {isLoading && !getAllAgentflows.data ? ( + + + + + + ) : ( + + {getAllAgentflows.data?.filter(filterFlows).map((data, index) => ( + goToCanvas(data)} data={data} images={images[data.id]} /> + ))} + + )} + + ) : ( + + )} + {!isLoading && (!getAllAgentflows.data || getAllAgentflows.data.length === 0) && ( + + + AgentsEmptySVG + +
No Agents Yet
+
+ )} +
+ )} + + + +
+ ) +} + +export default Agentflows diff --git a/packages/ui/src/views/apikey/APIKeyDialog.jsx b/packages/ui/src/views/apikey/APIKeyDialog.jsx index 6816a31090e..f305f13fb12 100644 --- a/packages/ui/src/views/apikey/APIKeyDialog.jsx +++ b/packages/ui/src/views/apikey/APIKeyDialog.jsx @@ -21,7 +21,7 @@ import { useTheme } from '@mui/material/styles' import { StyledButton } from '@/ui-component/button/StyledButton' // Icons -import { IconX, IconCopy } from '@tabler/icons' +import { IconX, IconCopy } from '@tabler/icons-react' // API import apikeyApi from '@/api/apikey' diff --git a/packages/ui/src/views/apikey/index.jsx b/packages/ui/src/views/apikey/index.jsx index 1a5705ab182..d0c3bd5665e 100644 --- a/packages/ui/src/views/apikey/index.jsx +++ b/packages/ui/src/views/apikey/index.jsx @@ -44,7 +44,7 @@ import useConfirm from '@/hooks/useConfirm' import useNotifier from '@/utils/useNotifier' // Icons -import { IconTrash, IconEdit, IconCopy, IconChevronsUp, IconChevronsDown, IconX, IconPlus, IconEye, IconEyeOff } from '@tabler/icons' +import { IconTrash, IconEdit, IconCopy, IconChevronsUp, IconChevronsDown, IconX, IconPlus, IconEye, IconEyeOff } from '@tabler/icons-react' import APIEmptySVG from '@/assets/images/api_empty.svg' // ==============================|| APIKey ||============================== // @@ -355,7 +355,7 @@ const APIKey = () => { APIEmptySVG diff --git a/packages/ui/src/views/assistants/AssistantDialog.jsx b/packages/ui/src/views/assistants/AssistantDialog.jsx index b4e1f55ec5a..eb2e1e34e8f 100644 --- a/packages/ui/src/views/assistants/AssistantDialog.jsx +++ b/packages/ui/src/views/assistants/AssistantDialog.jsx @@ -32,7 +32,7 @@ import DeleteConfirmDialog from './DeleteConfirmDialog' import AssistantVectorStoreDialog from './AssistantVectorStoreDialog' // Icons -import { IconX, IconPlus } from '@tabler/icons' +import { IconX, IconPlus } from '@tabler/icons-react' // API import assistantsApi from '@/api/assistants' @@ -46,6 +46,10 @@ import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' import { maxScroll } from '@/store/constant' const assistantAvailableModels = [ + { + label: 'gpt-4o', + name: 'gpt-4o' + }, { label: 'gpt-4-turbo', name: 'gpt-4-turbo' @@ -70,6 +74,10 @@ const assistantAvailableModels = [ label: 'gpt-3.5-turbo', name: 'gpt-3.5-turbo' }, + { + label: 'gpt-3.5-turbo-0125', + name: 'gpt-3.5-turbo-0125' + }, { label: 'gpt-3.5-turbo-1106', name: 'gpt-3.5-turbo-1106' diff --git a/packages/ui/src/views/assistants/AssistantVectorStoreDialog.jsx b/packages/ui/src/views/assistants/AssistantVectorStoreDialog.jsx index f6c09d5191c..e026583acf5 100644 --- a/packages/ui/src/views/assistants/AssistantVectorStoreDialog.jsx +++ b/packages/ui/src/views/assistants/AssistantVectorStoreDialog.jsx @@ -16,7 +16,7 @@ import { Dropdown } from '@/ui-component/dropdown/Dropdown' import { BackdropLoader } from '@/ui-component/loading/BackdropLoader' // Icons -import { IconX } from '@tabler/icons' +import { IconX } from '@tabler/icons-react' // API import assistantsApi from '@/api/assistants' diff --git a/packages/ui/src/views/assistants/index.jsx b/packages/ui/src/views/assistants/index.jsx index 1063752eb4d..85f9fc2aa0f 100644 --- a/packages/ui/src/views/assistants/index.jsx +++ b/packages/ui/src/views/assistants/index.jsx @@ -7,7 +7,7 @@ import { Box, Stack, Button, Skeleton } from '@mui/material' import MainCard from '@/ui-component/cards/MainCard' import ItemCard from '@/ui-component/cards/ItemCard' import { gridSpacing } from '@/store/constant' -import ToolEmptySVG from '@/assets/images/tools_empty.svg' +import AssistantEmptySVG from '@/assets/images/assistant_empty.svg' import { StyledButton } from '@/ui-component/button/StyledButton' import AssistantDialog from './AssistantDialog' import LoadAssistantDialog from './LoadAssistantDialog' @@ -19,7 +19,7 @@ import assistantsApi from '@/api/assistants' import useApi from '@/hooks/useApi' // icons -import { IconPlus, IconFileUpload } from '@tabler/icons' +import { IconPlus, IconFileUpload } from '@tabler/icons-react' import ViewHeader from '@/layout/MainLayout/ViewHeader' import ErrorBoundary from '@/ErrorBoundary' @@ -145,9 +145,9 @@ const Assistants = () => { ToolEmptySVG
No Assistants Added Yet
diff --git a/packages/ui/src/views/canvas/AddNodes.jsx b/packages/ui/src/views/canvas/AddNodes.jsx index 6439a04ffb1..af1fad29902 100644 --- a/packages/ui/src/views/canvas/AddNodes.jsx +++ b/packages/ui/src/views/canvas/AddNodes.jsx @@ -37,7 +37,7 @@ import Transitions from '@/ui-component/extended/Transitions' import { StyledFab } from '@/ui-component/button/StyledFab' // icons -import { IconPlus, IconSearch, IconMinus, IconX } from '@tabler/icons' +import { IconPlus, IconSearch, IconMinus, IconX } from '@tabler/icons-react' import LlamaindexPNG from '@/assets/images/llamaindex.png' import LangChainPNG from '@/assets/images/langchain.png' @@ -53,7 +53,10 @@ function a11yProps(index) { } } -const AddNodes = ({ nodesData, node }) => { +const blacklistCategoriesForAgentCanvas = ['Agents', 'Memory', 'Record Manager'] +const allowedAgentModel = {} + +const AddNodes = ({ nodesData, node, isAgentCanvas }) => { const theme = useTheme() const customization = useSelector((state) => state.customization) const dispatch = useDispatch() @@ -103,7 +106,17 @@ const AddNodes = ({ nodesData, node }) => { } const getSearchedNodes = (value) => { - const passed = nodesData.filter((nd) => { + if (isAgentCanvas) { + const nodes = nodesData.filter((nd) => !blacklistCategoriesForAgentCanvas.includes(nd.category)) + const passed = nodes.filter((nd) => { + const passesQuery = nd.name.toLowerCase().includes(value.toLowerCase()) + const passesCategory = nd.category.toLowerCase().includes(value.toLowerCase()) + return passesQuery || passesCategory + }) + return passed + } + const nodes = nodesData.filter((nd) => nd.category !== 'Multi Agents') + const passed = nodes.filter((nd) => { const passesQuery = nd.name.toLowerCase().includes(value.toLowerCase()) const passesCategory = nd.category.toLowerCase().includes(value.toLowerCase()) return passesQuery || passesCategory @@ -136,17 +149,57 @@ const AddNodes = ({ nodesData, node }) => { } const groupByCategory = (nodes, newTabValue, isFilter) => { - const taggedNodes = groupByTags(nodes, newTabValue) - const accordianCategories = {} - const result = taggedNodes.reduce(function (r, a) { - r[a.category] = r[a.category] || [] - r[a.category].push(a) - accordianCategories[a.category] = isFilter ? true : false - return r - }, Object.create(null)) - setNodes(result) - categorizeVectorStores(result, accordianCategories, isFilter) - setCategoryExpanded(accordianCategories) + if (isAgentCanvas) { + const accordianCategories = {} + const result = nodes.reduce(function (r, a) { + r[a.category] = r[a.category] || [] + r[a.category].push(a) + accordianCategories[a.category] = isFilter ? true : false + return r + }, Object.create(null)) + + const filteredResult = {} + for (const category in result) { + // Filter out blacklisted categories + if (!blacklistCategoriesForAgentCanvas.includes(category)) { + // Filter out LlamaIndex nodes + const nodes = result[category].filter((nd) => !nd.tags || !nd.tags.includes('LlamaIndex')) + if (!nodes.length) continue + + // Only allow specific models for specific categories + if (Object.keys(allowedAgentModel).includes(category)) { + const allowedModels = allowedAgentModel[category] + filteredResult[category] = nodes.filter((nd) => allowedModels.includes(nd.name)) + } else { + filteredResult[category] = nodes + } + } + } + setNodes(filteredResult) + categorizeVectorStores(filteredResult, accordianCategories, isFilter) + accordianCategories['Multi Agents'] = true + setCategoryExpanded(accordianCategories) + } else { + const taggedNodes = groupByTags(nodes, newTabValue) + const accordianCategories = {} + const result = taggedNodes.reduce(function (r, a) { + r[a.category] = r[a.category] || [] + r[a.category].push(a) + accordianCategories[a.category] = isFilter ? true : false + return r + }, Object.create(null)) + + const filteredResult = {} + for (const category in result) { + if (category === 'Multi Agents') { + continue + } + filteredResult[category] = result[category] + } + setNodes(filteredResult) + categorizeVectorStores(filteredResult, accordianCategories, isFilter) + setCategoryExpanded(accordianCategories) + } } const handleAccordionChange = (category) => (event, isExpanded) => { @@ -271,62 +324,64 @@ const AddNodes = ({ nodesData, node }) => { 'aria-label': 'weight' }} /> - - {['LangChain', 'LlamaIndex'].map((item, index) => ( - - + {['LangChain', 'LlamaIndex'].map((item, index) => ( + -
- } - iconPosition='start' - sx={{ minHeight: '50px', height: '50px' }} - key={index} - label={item} - {...a11yProps(index)} - > - ))} -
- BETA -
- + > + {item} + + } + iconPosition='start' + sx={{ minHeight: '50px', height: '50px' }} + key={index} + label={item} + {...a11yProps(index)} + > + ))} +
+ BETA +
+ + )} @@ -334,7 +389,11 @@ const AddNodes = ({ nodesData, node }) => { containerRef={(el) => { ps.current = el }} - style={{ height: '100%', maxHeight: 'calc(100vh - 380px)', overflowX: 'hidden' }} + style={{ + height: '100%', + maxHeight: `calc(100vh - ${isAgentCanvas ? '300' : '380'}px)`, + overflowX: 'hidden' + }} > { AddNodes.propTypes = { nodesData: PropTypes.array, - node: PropTypes.object + node: PropTypes.object, + isAgentCanvas: PropTypes.bool } export default AddNodes diff --git a/packages/ui/src/views/canvas/CanvasHeader.jsx b/packages/ui/src/views/canvas/CanvasHeader.jsx index 88afed789d3..c4d842cf2f5 100644 --- a/packages/ui/src/views/canvas/CanvasHeader.jsx +++ b/packages/ui/src/views/canvas/CanvasHeader.jsx @@ -8,7 +8,7 @@ import { useTheme } from '@mui/material/styles' import { Avatar, Box, ButtonBase, Typography, Stack, TextField } from '@mui/material' // icons -import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck, IconX, IconCode } from '@tabler/icons' +import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck, IconX, IconCode } from '@tabler/icons-react' // project imports import Settings from '@/views/settings' @@ -32,7 +32,7 @@ import ViewLeadsDialog from '@/ui-component/dialog/ViewLeadsDialog' // ==============================|| CANVAS HEADER ||============================== // -const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFlow }) => { +const CanvasHeader = ({ chatflow, isAgentCanvas, handleSaveFlow, handleDeleteFlow, handleLoadFlow }) => { const theme = useTheme() const dispatch = useDispatch() const navigate = useNavigate() @@ -54,6 +54,8 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl const [chatflowConfigurationDialogOpen, setChatflowConfigurationDialogOpen] = useState(false) const [chatflowConfigurationDialogProps, setChatflowConfigurationDialogProps] = useState({}) + const title = isAgentCanvas ? 'Agents' : 'Chatflow' + const updateChatflowApi = useApi(chatflowsApi.updateChatflow) const canvas = useSelector((state) => state.canvas) @@ -82,14 +84,17 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl setUpsertHistoryDialogOpen(true) } else if (setting === 'chatflowConfiguration') { setChatflowConfigurationDialogProps({ - title: 'Chatflow Configuration', + title: `${title} Configuration`, chatflow: chatflow }) setChatflowConfigurationDialogOpen(true) } else if (setting === 'duplicateChatflow') { try { - localStorage.setItem('duplicatedFlowData', chatflow.flowData) - window.open(`${uiBaseURL}/canvas`, '_blank') + let flowData = chatflow.flowData + const parsedFlowData = JSON.parse(flowData) + flowData = JSON.stringify(parsedFlowData) + localStorage.setItem('duplicatedFlowData', flowData) + window.open(`${uiBaseURL}/${isAgentCanvas ? 'agentcanvas' : 'canvas'}`, '_blank') } catch (e) { console.error(e) } @@ -99,7 +104,7 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl let dataStr = JSON.stringify(generateExportFlowData(flowData), null, 2) let dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr) - let exportFileDefaultName = `${chatflow.name} Chatflow.json` + let exportFileDefaultName = `${chatflow.name} ${title}.json` let linkElement = document.createElement('a') linkElement.setAttribute('href', dataUri) @@ -192,12 +197,12 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl // if configuration dialog is open, update its data if (chatflowConfigurationDialogOpen) { setChatflowConfigurationDialogProps({ - title: 'Chatflow Configuration', + title: `${title} Configuration`, chatflow }) } } - }, [chatflow, chatflowConfigurationDialogOpen]) + }, [chatflow, title, chatflowConfigurationDialogOpen]) return ( <> @@ -346,7 +351,7 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl )} - + setSettingsOpen(false)} onSettingsItemClick={onSettingsItemClick} onUploadFile={onUploadFile} + isAgentCanvas={isAgentCanvas} /> { + if (!templateValue) return '' + const obj = {} + const inputVariables = getInputVariables(templateValue) + for (const inputVariable of inputVariables) { + obj[inputVariable] = '' + } + if (Object.keys(obj).length) return JSON.stringify(obj) + return '' + } + const onEditJSONClicked = (value, inputParam) => { // Preset values if the field is format prompt values let inputValue = value if (inputParam.name === 'promptValues' && !value) { - const obj = {} const templateValue = - (data.inputs['template'] ?? '') + (data.inputs['systemMessagePrompt'] ?? '') + (data.inputs['humanMessagePrompt'] ?? '') - const inputVariables = getInputVariables(templateValue) - for (const inputVariable of inputVariables) { - obj[inputVariable] = '' - } - if (Object.keys(obj).length) inputValue = JSON.stringify(obj) + (data.inputs['template'] ?? '') + + (data.inputs['systemMessagePrompt'] ?? '') + + (data.inputs['humanMessagePrompt'] ?? '') + + (data.inputs['workerPrompt'] ?? '') + inputValue = getJSONValue(templateValue) } const dialogProp = { value: inputValue, @@ -386,7 +395,12 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA (data.inputs[inputParam.name] = newValue)} - value={data.inputs[inputParam.name] ?? inputParam.default ?? ''} + value={ + data.inputs[inputParam.name] || + inputParam.default || + getJSONValue(data.inputs['workerPrompt']) || + '' + } isDarkMode={customization.isDarkMode} /> )} diff --git a/packages/ui/src/views/canvas/StickyNote.jsx b/packages/ui/src/views/canvas/StickyNote.jsx index 73a0208fa53..7f5378a5257 100644 --- a/packages/ui/src/views/canvas/StickyNote.jsx +++ b/packages/ui/src/views/canvas/StickyNote.jsx @@ -9,7 +9,7 @@ import { useTheme } from '@mui/material/styles' import NodeCardWrapper from '@/ui-component/cards/NodeCardWrapper' import NodeTooltip from '@/ui-component/tooltip/NodeTooltip' import { IconButton, Box } from '@mui/material' -import { IconCopy, IconTrash } from '@tabler/icons' +import { IconCopy, IconTrash } from '@tabler/icons-react' import { Input } from '@/ui-component/input/Input' // const diff --git a/packages/ui/src/views/canvas/index.jsx b/packages/ui/src/views/canvas/index.jsx index 99f24b87ba9..42605054755 100644 --- a/packages/ui/src/views/canvas/index.jsx +++ b/packages/ui/src/views/canvas/index.jsx @@ -4,7 +4,6 @@ import 'reactflow/dist/style.css' import { useDispatch, useSelector } from 'react-redux' import { useNavigate, useLocation } from 'react-router-dom' -import { usePrompt } from '@/utils/usePrompt' import { REMOVE_DIRTY, SET_DIRTY, @@ -38,7 +37,7 @@ import useApi from '@/hooks/useApi' import useConfirm from '@/hooks/useConfirm' // icons -import { IconX, IconRefreshAlert } from '@tabler/icons' +import { IconX, IconRefreshAlert } from '@tabler/icons-react' // utils import { @@ -50,6 +49,7 @@ import { updateOutdatedNodeEdge } from '@/utils/genericHelper' import useNotifier from '@/utils/useNotifier' +import { usePrompt } from '@/utils/usePrompt' // const import { FLOWISE_CREDENTIAL_ID } from '@/store/constant' @@ -67,7 +67,10 @@ const Canvas = () => { const templateFlowData = state ? state.templateFlowData : '' const URLpath = document.location.pathname.toString().split('/') - const chatflowId = URLpath[URLpath.length - 1] === 'canvas' ? '' : URLpath[URLpath.length - 1] + const chatflowId = + URLpath[URLpath.length - 1] === 'canvas' || URLpath[URLpath.length - 1] === 'agentcanvas' ? '' : URLpath[URLpath.length - 1] + const isAgentCanvas = URLpath.includes('agentcanvas') ? true : false + const canvasTitle = URLpath.includes('agentcanvas') ? 'Agent' : 'Chatflow' const { confirm } = useConfirm() @@ -75,7 +78,6 @@ const Canvas = () => { const canvas = useSelector((state) => state.canvas) const [canvasDataStore, setCanvasDataStore] = useState(canvas) const [chatflow, setChatflow] = useState(null) - const { reactFlowInstance, setReactFlowInstance } = useContext(flowContext) // ==============================|| Snackbar ||============================== // @@ -99,7 +101,6 @@ const Canvas = () => { const getNodesApi = useApi(nodesApi.getAllNodes) const createNewChatflowApi = useApi(chatflowsApi.createNewChatflow) - const testChatflowApi = useApi(chatflowsApi.testChatflow) const updateChatflowApi = useApi(chatflowsApi.updateChatflow) const getSpecificChatflowApi = useApi(chatflowsApi.getSpecificChatflow) @@ -159,7 +160,7 @@ const Canvas = () => { setNodes(nodes) setEdges(flowData.edges || []) - setDirty() + setTimeout(() => setDirty(), 0) } catch (e) { console.error(e) } @@ -168,7 +169,7 @@ const Canvas = () => { const handleDeleteFlow = async () => { const confirmPayload = { title: `Delete`, - description: `Delete chatflow ${chatflow.name}?`, + description: `Delete ${canvasTitle} ${chatflow.name}?`, confirmButtonName: 'Delete', cancelButtonName: 'Cancel' } @@ -178,7 +179,7 @@ const Canvas = () => { try { await chatflowsApi.deleteChatflow(chatflow.id) localStorage.removeItem(`${chatflow.id}_INTERNAL`) - navigate('/') + navigate(isAgentCanvas ? '/agentflows' : '/') } catch (error) { enqueueSnackbar({ message: typeof error.response.data === 'object' ? error.response.data.message : error.response.data, @@ -221,7 +222,8 @@ const Canvas = () => { name: chatflowName, deployed: false, isPublic: false, - flowData + flowData, + type: isAgentCanvas ? 'MULTIAGENT' : 'CHATFLOW' } createNewChatflowApi.request(newChatflowBody) } else { @@ -339,7 +341,7 @@ const Canvas = () => { const saveChatflowSuccess = () => { dispatch({ type: REMOVE_DIRTY }) enqueueSnackbar({ - message: 'Chatflow saved', + message: `${canvasTitle} saved`, options: { key: new Date().getTime() + Math.random(), variant: 'success', @@ -404,7 +406,7 @@ const Canvas = () => { setEdges(initialFlow.edges || []) dispatch({ type: SET_CHATFLOW, chatflow }) } else if (getSpecificChatflowApi.error) { - errorFailed(`Failed to retrieve chatflow: ${getSpecificChatflowApi.error.response.data.message}`) + errorFailed(`Failed to retrieve ${canvasTitle}: ${getSpecificChatflowApi.error.response.data.message}`) } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -416,9 +418,9 @@ const Canvas = () => { const chatflow = createNewChatflowApi.data dispatch({ type: SET_CHATFLOW, chatflow }) saveChatflowSuccess() - window.history.replaceState(null, null, `/canvas/${chatflow.id}`) + window.history.replaceState(state, null, `/${isAgentCanvas ? 'agentcanvas' : 'canvas'}/${chatflow.id}`) } else if (createNewChatflowApi.error) { - errorFailed(`Failed to save chatflow: ${createNewChatflowApi.error.response.data.message}`) + errorFailed(`Failed to save ${canvasTitle}: ${createNewChatflowApi.error.response.data.message}`) } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -430,33 +432,12 @@ const Canvas = () => { dispatch({ type: SET_CHATFLOW, chatflow: updateChatflowApi.data }) saveChatflowSuccess() } else if (updateChatflowApi.error) { - errorFailed(`Failed to save chatflow: ${updateChatflowApi.error.response.data.message}`) + errorFailed(`Failed to save ${canvasTitle}: ${updateChatflowApi.error.response.data.message}`) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [updateChatflowApi.data, updateChatflowApi.error]) - // Test chatflow failed - useEffect(() => { - if (testChatflowApi.error) { - enqueueSnackbar({ - message: 'Test chatflow failed', - options: { - key: new Date().getTime() + Math.random(), - variant: 'error', - persist: true, - action: (key) => ( - - ) - } - }) - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [testChatflowApi.error]) - useEffect(() => { setChatflow(canvasDataStore.chatflow) if (canvasDataStore.chatflow) { @@ -485,7 +466,7 @@ const Canvas = () => { dispatch({ type: SET_CHATFLOW, chatflow: { - name: 'Untitled chatflow' + name: `Untitled ${canvasTitle}` } }) } @@ -550,6 +531,7 @@ const Canvas = () => { handleSaveFlow={handleSaveFlow} handleDeleteFlow={handleDeleteFlow} handleLoadFlow={handleLoadFlow} + isAgentCanvas={isAgentCanvas} /> @@ -582,7 +564,7 @@ const Canvas = () => { }} /> - + {isSyncNodesButtonEnabled && ( { )} {isUpsertButtonEnabled && } - + diff --git a/packages/ui/src/views/chatflows/APICodeDialog.jsx b/packages/ui/src/views/chatflows/APICodeDialog.jsx index 2b0111baac6..d479239cb46 100644 --- a/packages/ui/src/views/chatflows/APICodeDialog.jsx +++ b/packages/ui/src/views/chatflows/APICodeDialog.jsx @@ -14,7 +14,8 @@ import { Accordion, AccordionSummary, AccordionDetails, - Typography + Typography, + Stack } from '@mui/material' import { CopyBlock, atomOneDark } from 'react-code-blocks' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' @@ -35,7 +36,7 @@ import cURLSVG from '@/assets/images/cURL.svg' import EmbedSVG from '@/assets/images/embed.svg' import ShareChatbotSVG from '@/assets/images/sharing.png' import settingsSVG from '@/assets/images/settings.svg' -import { IconBulb } from '@tabler/icons' +import { IconBulb } from '@tabler/icons-react' // API import apiKeyApi from '@/api/apikey' @@ -118,16 +119,34 @@ const APICodeDialog = ({ show, dialogProps, onCancel }) => { updateChatflowApi.request(dialogProps.chatflowid, updateBody) } - const groupByNodeLabel = (nodes, isFilter = false) => { - const accordianNodes = {} - const result = nodes.reduce(function (r, a) { - r[a.node] = r[a.node] || [] - r[a.node].push(a) - accordianNodes[a.node] = isFilter ? true : false - return r - }, Object.create(null)) + const groupByNodeLabel = (nodes) => { + const result = {} + + nodes.forEach((item) => { + const { node, nodeId, label, name, type } = item + + if (!result[node]) { + result[node] = { + nodeIds: [], + params: [] + } + } + + if (!result[node].nodeIds.includes(nodeId)) result[node].nodeIds.push(nodeId) + + const param = { label, name, type } + + if (!result[node].params.some((existingParam) => JSON.stringify(existingParam) === JSON.stringify(param))) { + result[node].params.push(param) + } + }) + + // Sort the nodeIds array + for (const node in result) { + result[node].nodeIds.sort() + } + setNodeConfig(result) - setNodeConfigExpanded(accordianNodes) } const handleAccordionChange = (nodeLabel) => (event, isExpanded) => { @@ -481,12 +500,16 @@ query({ const getMultiConfigCodeWithFormData = (codeLang) => { if (codeLang === 'Python') { - return `body_data = { - "openAIApiKey[chatOpenAI_0]": "sk-my-openai-1st-key", - "openAIApiKey[openAIEmbeddings_0]": "sk-my-openai-2nd-key" + return `# Specify multiple values for a config parameter by specifying the node id +body_data = { + "openAIApiKey": { + "chatOpenAI_0": "sk-my-openai-1st-key", + "openAIEmbeddings_0": "sk-my-openai-2nd-key" + } }` } else if (codeLang === 'JavaScript') { - return `formData.append("openAIApiKey[chatOpenAI_0]", "sk-my-openai-1st-key") + return `// Specify multiple values for a config parameter by specifying the node id +formData.append("openAIApiKey[chatOpenAI_0]", "sk-my-openai-1st-key") formData.append("openAIApiKey[openAIEmbeddings_0]", "sk-my-openai-2nd-key")` } else if (codeLang === 'cURL') { return `-F "openAIApiKey[chatOpenAI_0]=sk-my-openai-1st-key" \\ @@ -619,35 +642,34 @@ formData.append("openAIApiKey[openAIEmbeddings_0]", "sk-my-openai-2nd-key")` aria-controls={`nodes-accordian-${nodeLabel}`} id={`nodes-accordian-header-${nodeLabel}`} > -
+ {nodeLabel} -
- - {nodeConfig[nodeLabel][0].nodeId} - -
-
+ {nodeConfig[nodeLabel].nodeIds.length > 0 && + nodeConfig[nodeLabel].nodeIds.map((nodeId, index) => ( +
+ + {nodeId} + +
+ ))} + { - // eslint-disable-next-line - const { node, nodeId, ...rest } = obj - return rest - })} - columns={Object.keys(nodeConfig[nodeLabel][0]).slice(-3)} + rows={nodeConfig[nodeLabel].params} + columns={Object.keys(nodeConfig[nodeLabel].params[0]).slice(-3)} /> diff --git a/packages/ui/src/views/chatflows/ShareChatbot.jsx b/packages/ui/src/views/chatflows/ShareChatbot.jsx index 24bbb114328..ebb622e027a 100644 --- a/packages/ui/src/views/chatflows/ShareChatbot.jsx +++ b/packages/ui/src/views/chatflows/ShareChatbot.jsx @@ -12,7 +12,7 @@ import { StyledButton } from '@/ui-component/button/StyledButton' import { TooltipWithParser } from '@/ui-component/tooltip/TooltipWithParser' // Icons -import { IconX, IconCopy, IconArrowUpRightCircle } from '@tabler/icons' +import { IconX, IconCopy, IconArrowUpRightCircle } from '@tabler/icons-react' // API import chatflowsApi from '@/api/chatflows' diff --git a/packages/ui/src/views/chatflows/index.jsx b/packages/ui/src/views/chatflows/index.jsx index 7ccf3e87a61..26452c9ea44 100644 --- a/packages/ui/src/views/chatflows/index.jsx +++ b/packages/ui/src/views/chatflows/index.jsx @@ -27,7 +27,7 @@ import useApi from '@/hooks/useApi' import { baseURL } from '@/store/constant' // icons -import { IconPlus, IconLayoutGrid, IconList } from '@tabler/icons' +import { IconPlus, IconLayoutGrid, IconList } from '@tabler/icons-react' // ==============================|| CHATFLOWS ||============================== // @@ -197,7 +197,7 @@ const Chatflows = () => { WorkflowEmptySVG diff --git a/packages/ui/src/views/chatmessage/ChatExpandDialog.jsx b/packages/ui/src/views/chatmessage/ChatExpandDialog.jsx index 4375b79ac3c..88b8e90c3d7 100644 --- a/packages/ui/src/views/chatmessage/ChatExpandDialog.jsx +++ b/packages/ui/src/views/chatmessage/ChatExpandDialog.jsx @@ -5,9 +5,9 @@ import { useSelector } from 'react-redux' import { Dialog, DialogContent, DialogTitle, Button } from '@mui/material' import { ChatMessage } from './ChatMessage' import { StyledButton } from '@/ui-component/button/StyledButton' -import { IconEraser } from '@tabler/icons' +import { IconEraser } from '@tabler/icons-react' -const ChatExpandDialog = ({ show, dialogProps, onClear, onCancel, previews, setPreviews }) => { +const ChatExpandDialog = ({ show, dialogProps, isAgentCanvas, onClear, onCancel, previews, setPreviews }) => { const portalElement = document.getElementById('portal') const customization = useSelector((state) => state.customization) @@ -50,6 +50,7 @@ const ChatExpandDialog = ({ show, dialogProps, onClear, onCancel, previews, setP { +export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setPreviews }) => { const theme = useTheme() const customization = useSelector((state) => state.customization) const ps = useRef() + const dispatch = useDispatch() + + useNotifier() + const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) + const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) + const [userInput, setUserInput] = useState('') const [loading, setLoading] = useState(false) const [messages, setMessages] = useState([ @@ -83,7 +107,8 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews const [isChatFlowAvailableForSpeech, setIsChatFlowAvailableForSpeech] = useState(false) const [sourceDialogOpen, setSourceDialogOpen] = useState(false) const [sourceDialogProps, setSourceDialogProps] = useState({}) - const [chatId, setChatId] = useState(undefined) + const [chatId, setChatId] = useState(uuidv4()) + const [isMessageStopping, setIsMessageStopping] = useState(false) const inputRef = useRef(null) const getChatmessageApi = useApi(chatmessageApi.getInternalChatmessageFromChatflow) @@ -287,6 +312,28 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews } } + const handleAbort = async () => { + setIsMessageStopping(true) + try { + await chatmessageApi.abortMessage(chatflowid, chatId) + } catch (error) { + setIsMessageStopping(false) + enqueueSnackbar({ + message: typeof error.response.data === 'object' ? error.response.data.message : error.response.data, + options: { + key: new Date().getTime() + Math.random(), + variant: 'error', + persist: true, + action: (key) => ( + + ) + } + }) + } + } + const handleDeletePreview = (itemToDelete) => { if (itemToDelete.type === 'file') { URL.revokeObjectURL(itemToDelete.preview) // Clean up for file @@ -357,6 +404,56 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews }) } + const updateLastMessageAgentReasoning = (agentReasoning) => { + setMessages((prevMessages) => { + let allMessages = [...cloneDeep(prevMessages)] + if (allMessages[allMessages.length - 1].type === 'userMessage') return allMessages + allMessages[allMessages.length - 1].agentReasoning = JSON.parse(agentReasoning) + return allMessages + }) + } + + const updateLastMessageNextAgent = (nextAgent) => { + setMessages((prevMessages) => { + let allMessages = [...cloneDeep(prevMessages)] + if (allMessages[allMessages.length - 1].type === 'userMessage') return allMessages + const lastAgentReasoning = allMessages[allMessages.length - 1].agentReasoning + if (lastAgentReasoning && lastAgentReasoning.length > 0) { + lastAgentReasoning.push({ nextAgent }) + } + allMessages[allMessages.length - 1].agentReasoning = lastAgentReasoning + return allMessages + }) + } + + const abortMessage = () => { + setIsMessageStopping(false) + setMessages((prevMessages) => { + let allMessages = [...cloneDeep(prevMessages)] + if (allMessages[allMessages.length - 1].type === 'userMessage') return allMessages + const lastAgentReasoning = allMessages[allMessages.length - 1].agentReasoning + if (lastAgentReasoning && lastAgentReasoning.length > 0) { + allMessages[allMessages.length - 1].agentReasoning = lastAgentReasoning.filter((reasoning) => !reasoning.nextAgent) + } + return allMessages + }) + setTimeout(() => { + inputRef.current?.focus() + }, 100) + enqueueSnackbar({ + message: 'Message stopped', + options: { + key: new Date().getTime() + Math.random(), + variant: 'success', + action: (key) => ( + + ) + } + }) + } + const updateLastMessageUsedTools = (usedTools) => { setMessages((prevMessages) => { let allMessages = [...cloneDeep(prevMessages)] @@ -441,7 +538,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews return allMessages }) - if (!chatId) setChatId(data.chatId) + setChatId(data.chatId) if (input === '' && data.question) { // the response contains the question even if it was in an audio format @@ -468,6 +565,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews sourceDocuments: data?.sourceDocuments, usedTools: data?.usedTools, fileAnnotations: data?.fileAnnotations, + agentReasoning: data?.agentReasoning, type: 'apiMessage', feedback: null } @@ -535,6 +633,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews if (message.sourceDocuments) obj.sourceDocuments = JSON.parse(message.sourceDocuments) if (message.usedTools) obj.usedTools = JSON.parse(message.usedTools) if (message.fileAnnotations) obj.fileAnnotations = JSON.parse(message.fileAnnotations) + if (message.agentReasoning) obj.agentReasoning = JSON.parse(message.agentReasoning) if (message.fileUploads) { obj.fileUploads = JSON.parse(message.fileUploads) obj.fileUploads.forEach((file) => { @@ -656,6 +755,12 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews socket.on('fileAnnotations', updateLastMessageFileAnnotations) socket.on('token', updateLastMessage) + + socket.on('agentReasoning', updateLastMessageAgentReasoning) + + socket.on('nextAgent', updateLastMessageNextAgent) + + socket.on('abort', abortMessage) } return () => { @@ -779,7 +884,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews const result = await leadsApi.addLead(body) if (result.data) { const data = result.data - if (!chatId) setChatId(data.chatId) + setChatId(data.chatId) setLocalStorageChatflow(chatflowid, data.chatId, { lead: { name: leadName, email: leadEmail, phone: leadPhone } }) setIsLeadSaved(true) setLeadEmail(leadEmail) @@ -865,7 +970,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews }} > {message.usedTools.map((tool, index) => { - return ( + return tool ? ( } onClick={() => onSourceDialogClick(tool, 'Used Tools')} /> - ) + ) : null })} )} @@ -925,6 +1030,183 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews })} )} + {message.agentReasoning && ( +
+ {message.agentReasoning.map((agent, index) => { + return agent.nextAgent ? ( + + + + + agentPNG + +
{agent.nextAgent}
+
+
+
+ ) : ( + + + + + agentPNG + +
{agent.agentName}
+
+ {agent.usedTools && agent.usedTools.length > 0 && ( +
+ {agent.usedTools.map((tool, index) => { + return tool !== null ? ( + } + onClick={() => onSourceDialogClick(tool, 'Used Tools')} + /> + ) : null + })} +
+ )} + {agent.messages.length > 0 && ( + + ) : ( + + {children} + + ) + } + }} + > + {agent.messages.length > 1 + ? agent.messages.join('\\n') + : agent.messages[0]} + + )} + {agent.instructions &&

{agent.instructions}

} + {agent.messages.length === 0 && !agent.instructions &&

Finished

} + {agent.sourceDocuments && agent.sourceDocuments.length > 0 && ( +
+ {removeDuplicateURL(agent).map((source, index) => { + const URL = + source && source.metadata && source.metadata.source + ? isValidURL(source.metadata.source) + : undefined + return ( + + URL + ? onURLClick(source.metadata.source) + : onSourceDialogClick(source) + } + /> + ) + })} +
+ )} +
+
+ ) + })} +
+ )}
{message.type === 'leadCaptureMessage' && !getLocalStorageChatflow(chatflowid)?.lead && @@ -1310,30 +1592,74 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews )} - - - {loading ? ( -
- -
- ) : ( - // Send icon SVG in input field - + {!isAgentCanvas && ( + + + {loading ? ( +
+ +
+ ) : ( + // Send icon SVG in input field + + )} +
+
+ )} + {isAgentCanvas && ( + <> + {!loading && ( + + + + + )} -
-
+ {loading && ( + + handleAbort()} + disabled={isMessageStopping} + > + {isMessageStopping ? ( +
+ +
+ ) : ( + + )} +
+
+ )} + + )} } /> @@ -1356,6 +1682,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews ChatMessage.propTypes = { open: PropTypes.bool, chatflowid: PropTypes.string, + isAgentCanvas: PropTypes.bool, isDialog: PropTypes.bool, previews: PropTypes.array, setPreviews: PropTypes.func diff --git a/packages/ui/src/views/chatmessage/ChatPopUp.jsx b/packages/ui/src/views/chatmessage/ChatPopUp.jsx index 6d0d31bcc96..05deb38da34 100644 --- a/packages/ui/src/views/chatmessage/ChatPopUp.jsx +++ b/packages/ui/src/views/chatmessage/ChatPopUp.jsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import { ClickAwayListener, Paper, Popper, Button } from '@mui/material' import { useTheme } from '@mui/material/styles' -import { IconMessage, IconX, IconEraser, IconArrowsMaximize } from '@tabler/icons' +import { IconMessage, IconX, IconEraser, IconArrowsMaximize } from '@tabler/icons-react' // project import import { StyledFab } from '@/ui-component/button/StyledFab' @@ -26,7 +26,7 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba // Utils import { getLocalStorageChatflow, removeLocalStorageChatHistory } from '@/utils/genericHelper' -export const ChatPopUp = ({ chatflowid }) => { +export const ChatPopUp = ({ chatflowid, isAgentCanvas }) => { const theme = useTheme() const { confirm } = useConfirm() const dispatch = useDispatch() @@ -201,7 +201,13 @@ export const ChatPopUp = ({ chatflowid }) => { boxShadow shadow={theme.shadows[16]} > - + @@ -211,6 +217,7 @@ export const ChatPopUp = ({ chatflowid }) => { setShowExpandDialog(false)} previews={previews} @@ -220,4 +227,4 @@ export const ChatPopUp = ({ chatflowid }) => { ) } -ChatPopUp.propTypes = { chatflowid: PropTypes.string } +ChatPopUp.propTypes = { chatflowid: PropTypes.string, isAgentCanvas: PropTypes.bool } diff --git a/packages/ui/src/views/credentials/AddEditCredentialDialog.jsx b/packages/ui/src/views/credentials/AddEditCredentialDialog.jsx index dfdfe9af261..604cfd578b0 100644 --- a/packages/ui/src/views/credentials/AddEditCredentialDialog.jsx +++ b/packages/ui/src/views/credentials/AddEditCredentialDialog.jsx @@ -14,7 +14,7 @@ import ConfirmDialog from '@/ui-component/dialog/ConfirmDialog' import CredentialInputHandler from './CredentialInputHandler' // Icons -import { IconX } from '@tabler/icons' +import { IconX } from '@tabler/icons-react' // API import credentialsApi from '@/api/credentials' diff --git a/packages/ui/src/views/credentials/CredentialInputHandler.jsx b/packages/ui/src/views/credentials/CredentialInputHandler.jsx index 9eab149d9b5..26411168865 100644 --- a/packages/ui/src/views/credentials/CredentialInputHandler.jsx +++ b/packages/ui/src/views/credentials/CredentialInputHandler.jsx @@ -4,7 +4,7 @@ import { useSelector } from 'react-redux' // material-ui import { Box, Typography, IconButton } from '@mui/material' -import { IconArrowsMaximize, IconAlertTriangle } from '@tabler/icons' +import { IconArrowsMaximize, IconAlertTriangle } from '@tabler/icons-react' // project import import { Dropdown } from '@/ui-component/dropdown/Dropdown' diff --git a/packages/ui/src/views/credentials/CredentialListDialog.jsx b/packages/ui/src/views/credentials/CredentialListDialog.jsx index 34c09b549b4..a6b19cb5c99 100644 --- a/packages/ui/src/views/credentials/CredentialListDialog.jsx +++ b/packages/ui/src/views/credentials/CredentialListDialog.jsx @@ -4,7 +4,7 @@ import { useDispatch } from 'react-redux' import PropTypes from 'prop-types' import { List, ListItemButton, Dialog, DialogContent, DialogTitle, Box, OutlinedInput, InputAdornment, Typography } from '@mui/material' import { useTheme } from '@mui/material/styles' -import { IconSearch, IconX } from '@tabler/icons' +import { IconSearch, IconX } from '@tabler/icons-react' // const import { baseURL } from '@/store/constant' diff --git a/packages/ui/src/views/credentials/index.jsx b/packages/ui/src/views/credentials/index.jsx index 13413ec799b..4509ea1dd50 100644 --- a/packages/ui/src/views/credentials/index.jsx +++ b/packages/ui/src/views/credentials/index.jsx @@ -40,7 +40,7 @@ import useConfirm from '@/hooks/useConfirm' import useNotifier from '@/utils/useNotifier' // Icons -import { IconTrash, IconEdit, IconX, IconPlus } from '@tabler/icons' +import { IconTrash, IconEdit, IconX, IconPlus } from '@tabler/icons-react' import CredentialEmptySVG from '@/assets/images/credential_empty.svg' // const diff --git a/packages/ui/src/views/docstore/AddDocStoreDialog.jsx b/packages/ui/src/views/docstore/AddDocStoreDialog.jsx index d03d9e6d98a..f77eb958805 100644 --- a/packages/ui/src/views/docstore/AddDocStoreDialog.jsx +++ b/packages/ui/src/views/docstore/AddDocStoreDialog.jsx @@ -17,7 +17,7 @@ import { StyledButton } from '@/ui-component/button/StyledButton' import ConfirmDialog from '@/ui-component/dialog/ConfirmDialog' // Icons -import { IconX, IconFiles } from '@tabler/icons' +import { IconX, IconFiles } from '@tabler/icons-react' // API import documentStoreApi from '@/api/documentstore' diff --git a/packages/ui/src/views/docstore/DocStoreInputHandler.jsx b/packages/ui/src/views/docstore/DocStoreInputHandler.jsx index 74b99e10064..2de05a58b3d 100644 --- a/packages/ui/src/views/docstore/DocStoreInputHandler.jsx +++ b/packages/ui/src/views/docstore/DocStoreInputHandler.jsx @@ -4,7 +4,7 @@ import { useSelector } from 'react-redux' // material-ui import { Box, Typography, IconButton, Button } from '@mui/material' -import { IconArrowsMaximize, IconAlertTriangle } from '@tabler/icons' +import { IconArrowsMaximize, IconAlertTriangle } from '@tabler/icons-react' // project import import { Dropdown } from '@/ui-component/dropdown/Dropdown' diff --git a/packages/ui/src/views/docstore/DocumentLoaderListDialog.jsx b/packages/ui/src/views/docstore/DocumentLoaderListDialog.jsx index c010ac4e527..a8722ed358d 100644 --- a/packages/ui/src/views/docstore/DocumentLoaderListDialog.jsx +++ b/packages/ui/src/views/docstore/DocumentLoaderListDialog.jsx @@ -4,7 +4,7 @@ import { useDispatch } from 'react-redux' import PropTypes from 'prop-types' import { List, ListItemButton, Dialog, DialogContent, DialogTitle, Box, OutlinedInput, InputAdornment, Typography } from '@mui/material' import { useTheme } from '@mui/material/styles' -import { IconSearch, IconX } from '@tabler/icons' +import { IconSearch, IconX } from '@tabler/icons-react' // API import documentStoreApi from '@/api/documentstore' diff --git a/packages/ui/src/views/docstore/DocumentStoreDetail.jsx b/packages/ui/src/views/docstore/DocumentStoreDetail.jsx index 226307d2d2a..f7eaba1ac93 100644 --- a/packages/ui/src/views/docstore/DocumentStoreDetail.jsx +++ b/packages/ui/src/views/docstore/DocumentStoreDetail.jsx @@ -42,7 +42,7 @@ import useConfirm from '@/hooks/useConfirm' import useNotifier from '@/utils/useNotifier' // icons -import { IconPlus, IconRefresh, IconScissors, IconTrash, IconX, IconVectorBezier2 } from '@tabler/icons' +import { IconPlus, IconRefresh, IconScissors, IconTrash, IconX, IconVectorBezier2 } from '@tabler/icons-react' import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' import FileDeleteIcon from '@mui/icons-material/Delete' import FileEditIcon from '@mui/icons-material/Edit' diff --git a/packages/ui/src/views/docstore/ExpandedChunkDialog.jsx b/packages/ui/src/views/docstore/ExpandedChunkDialog.jsx index 8f3c6c199f4..e1adc1f9342 100644 --- a/packages/ui/src/views/docstore/ExpandedChunkDialog.jsx +++ b/packages/ui/src/views/docstore/ExpandedChunkDialog.jsx @@ -7,7 +7,7 @@ import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' // Material import { Button, Dialog, IconButton, DialogContent, DialogTitle, Typography } from '@mui/material' -import { IconEdit, IconTrash, IconX, IconLanguage } from '@tabler/icons' +import { IconEdit, IconTrash, IconX, IconLanguage } from '@tabler/icons-react' // Project imports import { CodeEditor } from '@/ui-component/editor/CodeEditor' diff --git a/packages/ui/src/views/docstore/LoaderConfigPreviewChunks.jsx b/packages/ui/src/views/docstore/LoaderConfigPreviewChunks.jsx index de1ec068a97..91d7d736dfd 100644 --- a/packages/ui/src/views/docstore/LoaderConfigPreviewChunks.jsx +++ b/packages/ui/src/views/docstore/LoaderConfigPreviewChunks.jsx @@ -11,7 +11,7 @@ import useApi from '@/hooks/useApi' // Material-UI import { Skeleton, Toolbar, Box, Button, Card, CardContent, Grid, OutlinedInput, Stack, Typography } from '@mui/material' import { useTheme, styled } from '@mui/material/styles' -import { IconScissors, IconArrowLeft, IconDatabaseImport, IconBook, IconX, IconEye } from '@tabler/icons' +import { IconScissors, IconArrowLeft, IconDatabaseImport, IconBook, IconX, IconEye } from '@tabler/icons-react' // Project import import MainCard from '@/ui-component/cards/MainCard' diff --git a/packages/ui/src/views/docstore/ShowStoredChunks.jsx b/packages/ui/src/views/docstore/ShowStoredChunks.jsx index c3a38d11838..ebefe36ebc0 100644 --- a/packages/ui/src/views/docstore/ShowStoredChunks.jsx +++ b/packages/ui/src/views/docstore/ShowStoredChunks.jsx @@ -7,7 +7,7 @@ import ReactJson from 'flowise-react-json-view' import { Box, Card, Button, Grid, IconButton, Stack, Typography } from '@mui/material' import { useTheme, styled } from '@mui/material/styles' import CardContent from '@mui/material/CardContent' -import { IconLanguage, IconX, IconChevronLeft, IconChevronRight } from '@tabler/icons' +import { IconLanguage, IconX, IconChevronLeft, IconChevronRight } from '@tabler/icons-react' import chunks_emptySVG from '@/assets/images/chunks_empty.svg' // project imports diff --git a/packages/ui/src/views/docstore/index.jsx b/packages/ui/src/views/docstore/index.jsx index dd03c294aaa..cd3c8fd8af5 100644 --- a/packages/ui/src/views/docstore/index.jsx +++ b/packages/ui/src/views/docstore/index.jsx @@ -34,7 +34,7 @@ import useApi from '@/hooks/useApi' import documentsApi from '@/api/documentstore' // icons -import { IconPlus, IconLayoutGrid, IconList } from '@tabler/icons' +import { IconPlus, IconLayoutGrid, IconList } from '@tabler/icons-react' import doc_store_empty from '@/assets/images/doc_store_empty.svg' // const @@ -327,7 +327,7 @@ const Documents = () => { doc_store_empty diff --git a/packages/ui/src/views/marketplaces/MarketplaceCanvas.jsx b/packages/ui/src/views/marketplaces/MarketplaceCanvas.jsx index e256b7f5750..d807c4f0c38 100644 --- a/packages/ui/src/views/marketplaces/MarketplaceCanvas.jsx +++ b/packages/ui/src/views/marketplaces/MarketplaceCanvas.jsx @@ -46,8 +46,9 @@ const MarketplaceCanvas = () => { }, [flowData]) const onChatflowCopy = (flowData) => { + const isAgentCanvas = (flowData?.nodes || []).some((node) => node.data.category === 'Multi Agents') const templateFlowData = JSON.stringify(flowData) - navigate(`/canvas`, { state: { templateFlowData } }) + navigate(`/${isAgentCanvas ? 'agentcanvas' : 'canvas'}`, { state: { templateFlowData } }) } return ( diff --git a/packages/ui/src/views/marketplaces/MarketplaceCanvasHeader.jsx b/packages/ui/src/views/marketplaces/MarketplaceCanvasHeader.jsx index 57db0e22241..3fbe78f2766 100644 --- a/packages/ui/src/views/marketplaces/MarketplaceCanvasHeader.jsx +++ b/packages/ui/src/views/marketplaces/MarketplaceCanvasHeader.jsx @@ -7,7 +7,7 @@ import { Avatar, Box, ButtonBase, Typography, Stack } from '@mui/material' import { StyledButton } from '@/ui-component/button/StyledButton' // icons -import { IconCopy, IconChevronLeft } from '@tabler/icons' +import { IconCopy, IconChevronLeft } from '@tabler/icons-react' // ==============================|| CANVAS HEADER ||============================== // diff --git a/packages/ui/src/views/marketplaces/index.jsx b/packages/ui/src/views/marketplaces/index.jsx index 4ddf603e7a1..a4d997c20ef 100644 --- a/packages/ui/src/views/marketplaces/index.jsx +++ b/packages/ui/src/views/marketplaces/index.jsx @@ -18,7 +18,7 @@ import { Skeleton } from '@mui/material' import { useTheme } from '@mui/material/styles' -import { IconLayoutGrid, IconList } from '@tabler/icons' +import { IconLayoutGrid, IconList } from '@tabler/icons-react' // project imports import MainCard from '@/ui-component/cards/MainCard' @@ -63,7 +63,7 @@ TabPanel.propTypes = { } const badges = ['POPULAR', 'NEW'] -const types = ['Chatflow', 'Tool'] +const types = ['Chatflow', 'Agentflow', 'Tool'] const framework = ['Langchain', 'LlamaIndex'] const MenuProps = { PaperProps: { @@ -413,7 +413,7 @@ const Marketplace = () => { badgeContent={data.badge} color={data.badge === 'POPULAR' ? 'primary' : 'error'} > - {data.type === 'Chatflow' && ( + {(data.type === 'Chatflow' || data.type === 'Agentflow') && ( goToCanvas(data)} data={data} @@ -425,7 +425,7 @@ const Marketplace = () => { )} )} - {!data.badge && data.type === 'Chatflow' && ( + {!data.badge && (data.type === 'Chatflow' || data.type === 'Agentflow') && ( goToCanvas(data)} data={data} images={images[data.id]} /> )} {!data.badge && data.type === 'Tool' && ( diff --git a/packages/ui/src/views/settings/index.jsx b/packages/ui/src/views/settings/index.jsx index 41d22c42940..10900b623c0 100644 --- a/packages/ui/src/views/settings/index.jsx +++ b/packages/ui/src/views/settings/index.jsx @@ -14,10 +14,11 @@ import PerfectScrollbar from 'react-perfect-scrollbar' import MainCard from '@/ui-component/cards/MainCard' import Transitions from '@/ui-component/extended/Transitions' import settings from '@/menu-items/settings' +import agentsettings from '@/menu-items/agentsettings' // ==============================|| SETTINGS ||============================== // -const Settings = ({ chatflow, isSettingsOpen, anchorEl, onSettingsItemClick, onUploadFile, onClose }) => { +const Settings = ({ chatflow, isSettingsOpen, anchorEl, isAgentCanvas, onSettingsItemClick, onUploadFile, onClose }) => { const theme = useTheme() const [settingsMenu, setSettingsMenu] = useState([]) const customization = useSelector((state) => state.customization) @@ -42,13 +43,15 @@ const Settings = ({ chatflow, isSettingsOpen, anchorEl, onSettingsItemClick, onU useEffect(() => { if (chatflow && !chatflow.id) { - const settingsMenu = settings.children.filter((menu) => menu.id === 'loadChatflow') + const menus = isAgentCanvas ? agentsettings : settings + const settingsMenu = menus.children.filter((menu) => menu.id === 'loadChatflow') setSettingsMenu(settingsMenu) } else if (chatflow && chatflow.id) { - const settingsMenu = settings.children + const menus = isAgentCanvas ? agentsettings : settings + const settingsMenu = menus.children setSettingsMenu(settingsMenu) } - }, [chatflow]) + }, [chatflow, isAgentCanvas]) useEffect(() => { setOpen(isSettingsOpen) @@ -147,7 +150,8 @@ Settings.propTypes = { anchorEl: PropTypes.any, onSettingsItemClick: PropTypes.func, onUploadFile: PropTypes.func, - onClose: PropTypes.func + onClose: PropTypes.func, + isAgentCanvas: PropTypes.bool } export default Settings diff --git a/packages/ui/src/views/tools/ToolDialog.jsx b/packages/ui/src/views/tools/ToolDialog.jsx index 6b952c568b2..ff0e9e5b151 100644 --- a/packages/ui/src/views/tools/ToolDialog.jsx +++ b/packages/ui/src/views/tools/ToolDialog.jsx @@ -16,7 +16,7 @@ import { CodeEditor } from '@/ui-component/editor/CodeEditor' import HowToUseFunctionDialog from './HowToUseFunctionDialog' // Icons -import { IconX, IconFileDownload, IconPlus } from '@tabler/icons' +import { IconX, IconFileDownload, IconPlus } from '@tabler/icons-react' // API import toolsApi from '@/api/tools' diff --git a/packages/ui/src/views/tools/index.jsx b/packages/ui/src/views/tools/index.jsx index f433a99edf4..358f1e487f1 100644 --- a/packages/ui/src/views/tools/index.jsx +++ b/packages/ui/src/views/tools/index.jsx @@ -18,7 +18,7 @@ import toolsApi from '@/api/tools' import useApi from '@/hooks/useApi' // icons -import { IconPlus, IconFileUpload } from '@tabler/icons' +import { IconPlus, IconFileUpload } from '@tabler/icons-react' import ViewHeader from '@/layout/MainLayout/ViewHeader' import ErrorBoundary from '@/ErrorBoundary' @@ -165,7 +165,7 @@ const Tools = () => { ToolEmptySVG diff --git a/packages/ui/src/views/variables/AddEditVariableDialog.jsx b/packages/ui/src/views/variables/AddEditVariableDialog.jsx index 4ea917f1608..b097735bfab 100644 --- a/packages/ui/src/views/variables/AddEditVariableDialog.jsx +++ b/packages/ui/src/views/variables/AddEditVariableDialog.jsx @@ -12,7 +12,7 @@ import { StyledButton } from '@/ui-component/button/StyledButton' import ConfirmDialog from '@/ui-component/dialog/ConfirmDialog' // Icons -import { IconX, IconVariable } from '@tabler/icons' +import { IconX, IconVariable } from '@tabler/icons-react' // API import variablesApi from '@/api/variables' diff --git a/packages/ui/src/views/variables/index.jsx b/packages/ui/src/views/variables/index.jsx index c4436c94407..e9a1fbf48a5 100644 --- a/packages/ui/src/views/variables/index.jsx +++ b/packages/ui/src/views/variables/index.jsx @@ -39,7 +39,7 @@ import useConfirm from '@/hooks/useConfirm' import useNotifier from '@/utils/useNotifier' // Icons -import { IconTrash, IconEdit, IconX, IconPlus, IconVariable } from '@tabler/icons' +import { IconTrash, IconEdit, IconX, IconPlus, IconVariable } from '@tabler/icons-react' import VariablesEmptySVG from '@/assets/images/variables_empty.svg' // const @@ -218,7 +218,7 @@ const Variables = () => { VariablesEmptySVG diff --git a/packages/ui/src/views/vectorstore/UpsertHistoryDialog.jsx b/packages/ui/src/views/vectorstore/UpsertHistoryDialog.jsx index f3fd996d3dd..d8ddc58ff7e 100644 --- a/packages/ui/src/views/vectorstore/UpsertHistoryDialog.jsx +++ b/packages/ui/src/views/vectorstore/UpsertHistoryDialog.jsx @@ -32,7 +32,7 @@ import { } from '@mui/material' import { useTheme } from '@mui/material/styles' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { IconChevronsUp, IconChevronsDown, IconTrash, IconX } from '@tabler/icons' +import { IconChevronsUp, IconChevronsDown, IconTrash, IconX } from '@tabler/icons-react' // Project imports import { TableViewOnly } from '@/ui-component/table/Table' diff --git a/packages/ui/src/views/vectorstore/VectorStoreDialog.jsx b/packages/ui/src/views/vectorstore/VectorStoreDialog.jsx index 18110c48fd9..9d0075c93f6 100644 --- a/packages/ui/src/views/vectorstore/VectorStoreDialog.jsx +++ b/packages/ui/src/views/vectorstore/VectorStoreDialog.jsx @@ -23,7 +23,7 @@ import { CheckboxInput } from '@/ui-component/checkbox/Checkbox' import { BackdropLoader } from '@/ui-component/loading/BackdropLoader' import { TableViewOnly } from '@/ui-component/table/Table' -import { IconX } from '@tabler/icons' +import { IconX, IconBulb } from '@tabler/icons-react' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import pythonSVG from '@/assets/images/python.svg' import javascriptSVG from '@/assets/images/javascript.svg' @@ -216,6 +216,36 @@ query(formData).then((response) => { return '' } + const getMultiConfigCodeWithFormData = (codeLang) => { + if (codeLang === 'Python') { + return `# Specify multiple values for a config parameter by specifying the node id +body_data = { + "openAIApiKey": { + "chatOpenAI_0": "sk-my-openai-1st-key", + "openAIEmbeddings_0": "sk-my-openai-2nd-key" + } +}` + } else if (codeLang === 'JavaScript') { + return `// Specify multiple values for a config parameter by specifying the node id +formData.append("openAIApiKey[chatOpenAI_0]", "sk-my-openai-1st-key") +formData.append("openAIApiKey[openAIEmbeddings_0]", "sk-my-openai-2nd-key")` + } else if (codeLang === 'cURL') { + return `-F "openAIApiKey[chatOpenAI_0]=sk-my-openai-1st-key" \\ +-F "openAIApiKey[openAIEmbeddings_0]=sk-my-openai-2nd-key" \\` + } + } + + const getMultiConfigCode = () => { + return `{ + "overrideConfig": { + "openAIApiKey": { + "chatOpenAI_0": "sk-my-openai-1st-key", + "openAIEmbeddings_0": "sk-my-openai-2nd-key" + } + } +}` + } + const getLang = (codeLang) => { if (codeLang === 'Python') { return 'python' @@ -515,6 +545,44 @@ query(formData).then((response) => { showLineNumbers={false} wrapLines /> +
+
+ + + You can also specify multiple values for a config parameter by + specifying the node id + +
+
+ +
+
))}
diff --git a/packages/ui/src/views/vectorstore/VectorStorePopUp.jsx b/packages/ui/src/views/vectorstore/VectorStorePopUp.jsx index 657ff3b86be..899faf24a91 100644 --- a/packages/ui/src/views/vectorstore/VectorStorePopUp.jsx +++ b/packages/ui/src/views/vectorstore/VectorStorePopUp.jsx @@ -1,7 +1,7 @@ import { useState, useRef, useEffect } from 'react' import PropTypes from 'prop-types' -import { IconDatabaseImport, IconX } from '@tabler/icons' +import { IconDatabaseImport, IconX } from '@tabler/icons-react' // project import import { StyledFab } from '@/ui-component/button/StyledFab' diff --git a/packages/ui/vite.config.js b/packages/ui/vite.config.js index da529009c09..d67fe4432cc 100644 --- a/packages/ui/vite.config.js +++ b/packages/ui/vite.config.js @@ -12,6 +12,10 @@ export default defineConfig(async ({ mode }) => { '/api': { target: `http://localhost:${serverPort}`, changeOrigin: true + }, + '/socket.io': { + target: `http://localhost:${serverPort}`, + changeOrigin: true } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e22b171cea5..8e885ac9966 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,7 +32,7 @@ importers: version: 8.10.0(eslint@8.57.0) eslint-config-react-app: specifier: ^7.0.1 - version: 7.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(eslint@8.57.0)(jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(typescript@4.9.5) + version: 7.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(eslint@8.57.0)(jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4))(typescript@4.9.5) eslint-plugin-jsx-a11y: specifier: ^6.6.1 version: 6.8.0(eslint@8.57.0) @@ -96,12 +96,15 @@ importers: '@dqbd/tiktoken': specifier: ^1.0.7 version: 1.0.13 + '@e2b/code-interpreter': + specifier: ^0.0.5 + version: 0.0.5(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@elastic/elasticsearch': specifier: ^8.9.0 version: 8.12.2 '@getzep/zep-cloud': specifier: npm:@getzep/zep-js@next - version: '@getzep/zep-js@2.0.0-rc.4(@langchain/core@0.1.57)(langchain@0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0))' + version: '@getzep/zep-js@2.0.0-rc.4(@langchain/core@0.1.63)(langchain@0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)))' '@getzep/zep-js': specifier: ^0.9.0 version: 0.9.0 @@ -128,10 +131,10 @@ importers: version: 0.0.7(encoding@0.1.13) '@langchain/community': specifier: ^0.0.43 - version: 0.0.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0) + version: 0.0.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@langchain/core': - specifier: ^0.1.57 - version: 0.1.57 + specifier: ^0.1.63 + version: 0.1.63 '@langchain/google-genai': specifier: ^0.0.10 version: 0.0.10 @@ -141,6 +144,9 @@ importers: '@langchain/groq': specifier: ^0.0.8 version: 0.0.8(encoding@0.1.13) + '@langchain/langgraph': + specifier: ^0.0.12 + version: 0.0.12 '@langchain/mistralai': specifier: ^0.0.19 version: 0.0.19(encoding@0.1.13) @@ -148,8 +154,8 @@ importers: specifier: ^0.0.1 version: 0.0.1(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1) '@langchain/openai': - specifier: ^0.0.28 - version: 0.0.28(encoding@0.1.13) + specifier: ^0.0.30 + version: 0.0.30(encoding@0.1.13) '@langchain/pinecone': specifier: ^0.0.3 version: 0.0.3 @@ -173,7 +179,7 @@ importers: version: 1.8.1(typescript@4.9.5) '@supabase/supabase-js': specifier: ^2.29.0 - version: 2.39.8 + version: 2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@types/js-yaml': specifier: ^4.0.5 version: 4.0.9 @@ -194,10 +200,10 @@ importers: version: 2.9.3 assemblyai: specifier: ^4.2.2 - version: 4.3.2 + version: 4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) axios: specifier: 1.6.2 - version: 1.6.2 + version: 1.6.2(debug@4.3.4) cheerio: specifier: ^1.0.0-rc.12 version: 1.0.0-rc.12 @@ -245,19 +251,19 @@ importers: version: 5.3.2 jsdom: specifier: ^22.1.0 - version: 22.1.0(canvas@2.11.2(encoding@0.1.13)) + version: 22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) jsonpointer: specifier: ^5.0.1 version: 5.0.1 langchain: - specifier: ^0.1.33 - version: 0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0) + specifier: ^0.1.37 + version: 0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) langfuse: specifier: 3.3.4 version: 3.3.4 langfuse-langchain: specifier: ^3.3.4 - version: 3.3.4(langchain@0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0)) + version: 3.3.4(langchain@0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))) langsmith: specifier: 0.1.6 version: 0.1.6 @@ -266,7 +272,7 @@ importers: version: 4.1.3 llamaindex: specifier: ^0.2.1 - version: 0.2.1(@google/generative-ai@0.7.0)(encoding@0.1.13)(gcp-metadata@6.1.0(encoding@0.1.13))(node-fetch@2.7.0(encoding@0.1.13))(socks@2.8.1)(typescript@4.9.5) + version: 0.2.1(@google/generative-ai@0.7.0)(bufferutil@4.0.8)(encoding@0.1.13)(gcp-metadata@6.1.0(encoding@0.1.13))(node-fetch@2.7.0(encoding@0.1.13))(socks@2.8.1)(typescript@4.9.5)(utf-8-validate@6.0.4) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -314,10 +320,10 @@ importers: version: 1.42.1 puppeteer: specifier: ^20.7.1 - version: 20.9.0(encoding@0.1.13)(typescript@4.9.5) + version: 20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4) pyodide: specifier: '>=0.21.0-alpha.2' - version: 0.25.0 + version: 0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) redis: specifier: ^4.6.7 version: 4.6.13 @@ -326,7 +332,7 @@ importers: version: 0.18.1 socket.io: specifier: ^4.6.1 - version: 4.7.4 + version: 4.7.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) srt-parser-2: specifier: ^1.2.3 version: 1.2.3 @@ -344,7 +350,7 @@ importers: version: 3.12.0 ws: specifier: ^8.9.0 - version: 8.16.0 + version: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) zod: specifier: ^3.22.4 version: 3.22.4 @@ -486,7 +492,7 @@ importers: version: 2.12.1 socket.io: specifier: ^4.6.1 - version: 4.7.4 + version: 4.7.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) sqlite3: specifier: ^5.1.6 version: 5.1.7 @@ -581,9 +587,9 @@ importers: '@mui/x-data-grid': specifier: 6.8.0 version: 6.8.0(@mui/material@5.15.0(@emotion/react@11.11.4(@types/react@18.2.65)(react@18.2.0))(@emotion/styled@11.11.0(@emotion/react@11.11.4(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mui/system@5.15.12(@emotion/react@11.11.4(@types/react@18.2.65)(react@18.2.0))(@emotion/styled@11.11.0(@emotion/react@11.11.4(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react@18.2.0))(@types/react@18.2.65)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@tabler/icons': - specifier: ^1.39.1 - version: 1.119.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@tabler/icons-react': + specifier: ^3.3.0 + version: 3.3.0(react@18.2.0) '@uiw/codemirror-theme-sublime': specifier: ^4.21.21 version: 4.21.24(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.25.1) @@ -604,10 +610,10 @@ importers: version: 16.4.5 flowise-embed: specifier: latest - version: 1.2.4 + version: 1.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4) flowise-embed-react: specifier: latest - version: 1.0.2(@types/node@20.11.26)(flowise-embed@1.2.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.1)(terser@5.29.1)(typescript@4.9.5) + version: 1.0.2(@types/node@20.11.26)(flowise-embed@1.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.1)(terser@5.29.1)(typescript@4.9.5) flowise-react-json-view: specifier: '*' version: 1.21.7(@types/react@18.2.65)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -679,7 +685,7 @@ importers: version: 4.2.1 rehype-mathjax: specifier: ^4.0.2 - version: 4.0.3(canvas@2.11.2(encoding@0.1.13)) + version: 4.0.3(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) rehype-raw: specifier: ^7.0.0 version: 7.0.0 @@ -691,7 +697,7 @@ importers: version: 5.1.1 socket.io-client: specifier: ^4.6.1 - version: 4.7.4 + version: 4.7.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) uuid: specifier: ^9.0.1 version: 9.0.1 @@ -722,7 +728,7 @@ importers: version: 3.3.1(prettier@3.2.5) react-scripts: specifier: ^5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(@swc/core@1.4.6)(@types/babel__core@7.20.5)(canvas@2.11.2(encoding@0.1.13))(eslint@8.57.0)(react@18.2.0)(sass@1.71.1)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(type-fest@4.12.0)(typescript@4.9.5) + version: 5.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(@swc/core@1.4.6)(@types/babel__core@7.20.5)(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(eslint@8.57.0)(react@18.2.0)(sass@1.71.1)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(type-fest@4.12.0)(typescript@4.9.5)(utf-8-validate@6.0.4) rimraf: specifier: ^5.0.5 version: 5.0.5 @@ -2364,6 +2370,10 @@ packages: '@dqbd/tiktoken@1.0.13': resolution: { integrity: sha512-941kjlHjfI97l6NuH/AwuXV4mHuVnRooDcHNSlzi98hz+4ug3wT4gJcWjSwSZHqeGAEn90lC9sFD+8a9d5Jvxg== } + '@e2b/code-interpreter@0.0.5': + resolution: { integrity: sha512-ToFQ6N6EU8t91z3EJzh+mG+zf7uK8I1PRLWeu1f3bPS0pAJfM0puzBWOB3XlF9A9R5zZu/g8iO1gGPQXzXY5vA== } + engines: { node: '>=18' } + '@elastic/elasticsearch@8.12.2': resolution: { integrity: sha512-04NvH3LIgcv1Uwguorfw2WwzC9Lhfsqs9f0L6uq6MrCw0lqe/HOQ6E8vJ6EkHAA15iEfbhtxOtenbZVVcE+mAQ== } engines: { node: '>=18' } @@ -3552,8 +3562,8 @@ packages: ws: optional: true - '@langchain/core@0.1.57': - resolution: { integrity: sha512-6wOwidPkkRcANrOKl88+YYpm3jHfpg6W8EqZHQCImSAlxdEhyDSq2eeQKHOPCFCrfNWkClaNn+Wlzzz4Qwf9Tg== } + '@langchain/core@0.1.63': + resolution: { integrity: sha512-+fjyYi8wy6x1P+Ee1RWfIIEyxd9Ee9jksEwvrggPwwI/p45kIDTdYTblXsM13y4mNWTiACyLSdbwnPaxxdoz+w== } engines: { node: '>=18' } '@langchain/google-common@0.0.9': @@ -3576,6 +3586,10 @@ packages: resolution: { integrity: sha512-xqbe35K+12fiYtC/uqkaTT4AXxqL5uvhCrHzc+nBoFkTwM6YfTFE1ch95RZ5G2JnK1U9pKAre/trUSzlU1/6Kg== } engines: { node: '>=18' } + '@langchain/langgraph@0.0.12': + resolution: { integrity: sha512-f1N5eV3w7Y59P3rSjgNmjYoqghAPuxRUQTKX922OOhwYT0vmPVlmi99aduRHXK1oJDA3tVQCqrUkDV6D154Pnw== } + engines: { node: '>=18' } + '@langchain/mistralai@0.0.19': resolution: { integrity: sha512-Uin/jve1NCZLAFa9dpOKzE3Y2+uSnMJQX5ria9vO3lnTGRlvBwcMhyGDoTYdI+gnQgHH4ceBoIBzJDlVG+WVWw== } engines: { node: '>=18' } @@ -3584,14 +3598,18 @@ packages: resolution: { integrity: sha512-5CWh73s7D9/WraXcZJTqc6VRkITNe71G4uXBO/KwtE1E/7DlYT8EvWzX6Er+HvVp1EsBGlcJGUp9St/lvbfrPg== } engines: { node: '>=18' } - '@langchain/openai@0.0.28': - resolution: { integrity: sha512-2s1RA3/eAnz4ahdzsMPBna9hfAqpFNlWdHiPxVGZ5yrhXsbLWWoPcF+22LCk9t0HJKtazi2GCIWc0HVXH9Abig== } + '@langchain/openai@0.0.30': + resolution: { integrity: sha512-FgKl+bJFl9nDWynfYHb2A3VeTtzgEyzOM/DJZvRuVJ8yYejrLL/tE50G37gDeHOoBTm/12liLY4qhB71ONCVRA== } engines: { node: '>=18' } '@langchain/pinecone@0.0.3': resolution: { integrity: sha512-uhmGdiF6OLL583kQNMdKl799+3E1nQphrZ4a/Y/yQcXKUPVNZYwNLUimK1ws80RBhfqR7DKvywkvERoOsvCDlA== } engines: { node: '>=18' } + '@langchain/textsplitters@0.0.1': + resolution: { integrity: sha512-DqYsdZ/W2e4DlC8uFEFkYMtlAAmtDJgEJIl59XkueCQ0yNIMi1r9zpiRykaK/hBNEwE8FnQxixGj3mXwVTerdQ== } + engines: { node: '>=18' } + '@langchain/weaviate@0.0.1': resolution: { integrity: sha512-Lf6zgTf6i/fsPNlkDxPRLA3LEz2Wwgk6LNe54dByt0oZM4W+N4n5n/gDwojsXAKNEF5alXUv2N6yAOcUuXSbxg== } engines: { node: '>=18' } @@ -4597,16 +4615,13 @@ packages: resolution: { integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== } engines: { node: '>=10' } - '@tabler/icons@1.119.0': - resolution: { integrity: sha512-Fk3Qq4w2SXcTjc/n1cuL5bccPkylrOMo7cYpQIf/yw6zP76LQV9dtLcHQUjFiUnaYuswR645CnURIhlafyAh9g== } + '@tabler/icons-react@3.3.0': + resolution: { integrity: sha512-Qn1Po+0gErh1zCWlaOdoVoGqeonWfSuiboYgwZBs6PIJNsj7yr3bIa4BkHmgJgtlXLT9LvCzt/RvwlgjxLfjjg== } peerDependencies: - react: ^16.x || 17.x || 18.x - react-dom: ^16.x || 17.x || 18.x - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + react: '>= 16' + + '@tabler/icons@3.3.0': + resolution: { integrity: sha512-PLVe9d7b59sKytbx00KgeGhQG3N176Ezv8YMmsnSz4s0ifDzMWlp/h2wEfQZ0ZNe8e377GY2OW6kovUe3Rnd0g== } '@testing-library/dom@9.3.4': resolution: { integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ== } @@ -6314,6 +6329,10 @@ packages: buffer@6.0.3: resolution: { integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== } + bufferutil@4.0.8: + resolution: { integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== } + engines: { node: '>=6.14.2' } + builtin-modules@3.3.0: resolution: { integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== } engines: { node: '>=6' } @@ -7585,6 +7604,10 @@ packages: duplexify@4.1.3: resolution: { integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== } + e2b@0.16.1: + resolution: { integrity: sha512-2L1R/REEB+EezD4Q4MmcXXNATjvCYov2lv/69+PY6V95+wl1PZblIMTYAe7USxX6P6sqANxNs+kXqZr6RvXkSw== } + engines: { node: '>=18' } + each-props@1.3.2: resolution: { integrity: sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA== } @@ -8416,8 +8439,8 @@ packages: flowise-embed: '*' react: 18.x - flowise-embed@1.2.4: - resolution: { integrity: sha512-Cj0R4iOoAx585RbQn868NVzkgrO9U51jNlPujrnWJnLA+lwibT+EpHxacuO4Bio/JtYL/MJFztYleeuWIlKMJw== } + flowise-embed@1.2.6: + resolution: { integrity: sha512-rBl4QhcxY91V2fOm/L1kuwQSyQjimdTLT4uss7Lw9XBbOFQTVflJnzDxttp5an/pQcxQ+Y1TWCM/twMH05BV/g== } flowise-react-json-view@1.21.7: resolution: { integrity: sha512-oFjwtSLJkUWk6waLh8heCQ4o9b60FJRA2X8LefaZp5WaJvj/Rr2HILjk+ocf1JkfTcq8jc6t2jfIybg4leWsaQ== } @@ -9829,6 +9852,11 @@ packages: isomorphic-fetch@3.0.0: resolution: { integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== } + isomorphic-ws@5.0.0: + resolution: { integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== } + peerDependencies: + ws: '*' + isstream@0.1.2: resolution: { integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== } @@ -10072,6 +10100,9 @@ packages: js-tiktoken@1.0.10: resolution: { integrity: sha512-ZoSxbGjvGyMT13x6ACo9ebhDha/0FHdKA+OsQcMOWcm1Zs7r90Rhk5lhERLzji+3rA7EKpXCgwXcM5fF3DMpdA== } + js-tiktoken@1.0.12: + resolution: { integrity: sha512-L7wURW1fH9Qaext0VzaUDpFGVQgjkdE3Dgsy9/+yXyGEpBKnylTd0mU0bfbNkKDlXRb6TEsZkwuflu1B8uQbJQ== } + js-tokens@3.0.2: resolution: { integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg== } @@ -10289,8 +10320,8 @@ packages: kuler@2.0.0: resolution: { integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== } - langchain@0.1.33: - resolution: { integrity: sha512-IrRd839x8eAmDutHNDMHGzIjufyWt/ckJrnRB2WifIJmtLWNRNQo5jZd7toeBU0UOVOQxoPtQGYf8lR0ar7vIQ== } + langchain@0.1.37: + resolution: { integrity: sha512-rpaLEJtRrLYhAViEp7/aHfSkxbgSqHJ5n10tXv3o4kHP/wOin85RpTgewwvGjEaKc3797jOg+sLSk6a7e0UlMg== } engines: { node: '>=18' } peerDependencies: '@aws-sdk/client-s3': ^3.310.0 @@ -10298,11 +10329,13 @@ packages: '@aws-sdk/client-sfn': ^3.310.0 '@aws-sdk/credential-provider-node': ^3.388.0 '@azure/storage-blob': ^12.15.0 + '@browserbasehq/sdk': '*' '@gomomento/sdk': ^1.51.1 '@gomomento/sdk-core': ^1.51.1 '@gomomento/sdk-web': ^1.51.1 '@google-ai/generativelanguage': ^0.2.1 '@google-cloud/storage': ^6.10.1 || ^7.7.0 + '@mendable/firecrawl-js': ^0.0.13 '@notionhq/client': ^2.2.10 '@pinecone-database/pinecone': '*' '@supabase/supabase-js': ^2.10.0 @@ -10355,6 +10388,8 @@ packages: optional: true '@azure/storage-blob': optional: true + '@browserbasehq/sdk': + optional: true '@gomomento/sdk': optional: true '@gomomento/sdk-core': @@ -10365,6 +10400,8 @@ packages: optional: true '@google-cloud/storage': optional: true + '@mendable/firecrawl-js': + optional: true '@notionhq/client': optional: true '@pinecone-database/pinecone': @@ -11569,6 +11606,10 @@ packages: resolution: { integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== } engines: { node: '>= 6.13.0' } + node-gyp-build@4.8.1: + resolution: { integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw== } + hasBin: true + node-gyp@8.4.1: resolution: { integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== } engines: { node: '>= 10.12.0' } @@ -11923,6 +11964,10 @@ packages: openapi-types@12.1.3: resolution: { integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== } + openapi-typescript-fetch@1.1.3: + resolution: { integrity: sha512-smLZPck4OkKMNExcw8jMgrMOGgVGx2N/s6DbKL2ftNl77g5HfoGpZGFy79RBzU/EkaO0OZpwBnslfdBfh7ZcWg== } + engines: { node: '>= 12.0.0', npm: '>= 7.0.0' } + option-cache@3.5.0: resolution: { integrity: sha512-Hr14410H8ajAHeUirXZtuE9drwy8e85l0CssHB/k7Y6nRkleKsGAzB/gwltUzsnIqr9Y+7ZQ+H16GYWAJH3PVg== } engines: { node: '>=0.10.0' } @@ -12150,6 +12195,9 @@ packages: password-prompt@1.1.3: resolution: { integrity: sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw== } + path-browserify@1.0.1: + resolution: { integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== } + path-dirname@1.0.2: resolution: { integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q== } @@ -15388,6 +15436,10 @@ packages: resolution: { integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== } engines: { node: '>=0.10.0' } + utf-8-validate@6.0.4: + resolution: { integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ== } + engines: { node: '>=6.14.2' } + util-deprecate@1.0.2: resolution: { integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== } @@ -18717,7 +18769,7 @@ snapshots: '@datastax/astra-db-ts@0.1.4': dependencies: - axios: 1.6.2 + axios: 1.6.2(debug@4.3.4) bson: 6.4.0 winston: 3.12.0 transitivePeerDependencies: @@ -18725,6 +18777,15 @@ snapshots: '@dqbd/tiktoken@1.0.13': {} + '@e2b/code-interpreter@0.0.5(bufferutil@4.0.8)(utf-8-validate@6.0.4)': + dependencies: + e2b: 0.16.1 + isomorphic-ws: 5.0.0(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@elastic/elasticsearch@8.12.2': dependencies: '@elastic/transport': 8.4.1 @@ -18734,7 +18795,7 @@ snapshots: '@elastic/transport@8.4.1': dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) hpagent: 1.2.0 ms: 2.1.3 secure-json-parse: 2.7.0 @@ -18977,7 +19038,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -19017,14 +19078,14 @@ snapshots: semver: 7.6.0 typescript: 5.4.2 - '@getzep/zep-js@2.0.0-rc.4(@langchain/core@0.1.57)(langchain@0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0))': + '@getzep/zep-js@2.0.0-rc.4(@langchain/core@0.1.63)(langchain@0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)))': dependencies: '@supercharge/promise-pool': 3.1.1 semver: 7.6.0 typescript: 5.4.2 optionalDependencies: - '@langchain/core': 0.1.57 - langchain: 0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0) + '@langchain/core': 0.1.63 + langchain: 0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@gomomento/generated-types@0.106.1(encoding@0.1.13)': dependencies: @@ -19114,7 +19175,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -19168,7 +19229,7 @@ snapshots: jest-util: 28.1.3 slash: 3.0.0 - '@jest/core@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))': + '@jest/core@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4)': dependencies: '@jest/console': 27.5.1 '@jest/reporters': 27.5.1 @@ -19182,13 +19243,13 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 27.5.1 - jest-config: 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + jest-config: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) jest-haste-map: 27.5.1 jest-message-util: 27.5.1 jest-regex-util: 27.5.1 jest-resolve: 27.5.1 jest-resolve-dependencies: 27.5.1 - jest-runner: 27.5.1(canvas@2.11.2(encoding@0.1.13)) + jest-runner: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) jest-runtime: 27.5.1 jest-snapshot: 27.5.1 jest-util: 27.5.1 @@ -19435,7 +19496,7 @@ snapshots: '@langchain/anthropic@0.1.14(encoding@0.1.13)': dependencies: '@anthropic-ai/sdk': 0.20.4(encoding@0.1.13) - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 fast-xml-parser: 4.3.5 zod: 3.22.4 zod-to-json-schema: 3.22.4(zod@3.22.4) @@ -19444,15 +19505,15 @@ snapshots: '@langchain/cohere@0.0.7(encoding@0.1.13)': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 cohere-ai: 7.9.3(encoding@0.1.13) transitivePeerDependencies: - encoding - '@langchain/community@0.0.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0)': + '@langchain/community@0.0.43(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - '@langchain/core': 0.1.57 - '@langchain/openai': 0.0.28(encoding@0.1.13) + '@langchain/core': 0.1.63 + '@langchain/openai': 0.0.30(encoding@0.1.13) expr-eval: 2.0.2 flat: 5.0.2 langsmith: 0.1.6 @@ -19478,7 +19539,7 @@ snapshots: '@smithy/signature-v4': 2.1.4 '@smithy/util-utf8': 2.2.0 '@supabase/postgrest-js': 1.9.2 - '@supabase/supabase-js': 2.39.8 + '@supabase/supabase-js': 2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@upstash/redis': 1.22.1(encoding@0.1.13) '@upstash/vector': 1.0.7 '@xenova/transformers': 2.16.0 @@ -19490,7 +19551,7 @@ snapshots: google-auth-library: 9.6.3(encoding@0.1.13) html-to-text: 9.0.5 ioredis: 5.3.2 - jsdom: 22.1.0(canvas@2.11.2(encoding@0.1.13)) + jsdom: 22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) lodash: 4.17.21 lunary: 0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0) mongodb: 6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1) @@ -19501,14 +19562,14 @@ snapshots: replicate: 0.18.1 typeorm: 0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) weaviate-ts-client: 1.6.0(encoding@0.1.13)(graphql@16.8.1) - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - encoding - '@langchain/community@0.0.48(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0)': + '@langchain/community@0.0.48(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - '@langchain/core': 0.1.57 - '@langchain/openai': 0.0.28(encoding@0.1.13) + '@langchain/core': 0.1.63 + '@langchain/openai': 0.0.30(encoding@0.1.13) expr-eval: 2.0.2 flat: 5.0.2 langsmith: 0.1.6 @@ -19535,7 +19596,7 @@ snapshots: '@smithy/signature-v4': 2.1.4 '@smithy/util-utf8': 2.2.0 '@supabase/postgrest-js': 1.9.2 - '@supabase/supabase-js': 2.39.8 + '@supabase/supabase-js': 2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@upstash/redis': 1.22.1(encoding@0.1.13) '@upstash/vector': 1.0.7 '@xenova/transformers': 2.16.0 @@ -19547,7 +19608,7 @@ snapshots: google-auth-library: 9.6.3(encoding@0.1.13) html-to-text: 9.0.5 ioredis: 5.3.2 - jsdom: 22.1.0(canvas@2.11.2(encoding@0.1.13)) + jsdom: 22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) lodash: 4.17.21 lunary: 0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0) mongodb: 6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1) @@ -19558,27 +19619,28 @@ snapshots: replicate: 0.18.1 typeorm: 0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) weaviate-ts-client: 1.6.0(encoding@0.1.13)(graphql@16.8.1) - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - encoding - '@langchain/core@0.1.57': + '@langchain/core@0.1.63': dependencies: ansi-styles: 5.2.0 camelcase: 6.3.0 decamelize: 1.2.0 - js-tiktoken: 1.0.10 + js-tiktoken: 1.0.12 langsmith: 0.1.13 ml-distance: 4.0.1 + mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 uuid: 9.0.1 zod: 3.22.4 - zod-to-json-schema: 3.22.4(zod@3.22.4) + zod-to-json-schema: 3.22.5(zod@3.22.4) '@langchain/google-common@0.0.9(zod@3.22.4)': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 uuid: 9.0.1 zod-to-json-schema: 3.22.5(zod@3.22.4) transitivePeerDependencies: @@ -19586,7 +19648,7 @@ snapshots: '@langchain/google-gauth@0.0.5(encoding@0.1.13)(zod@3.22.4)': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 '@langchain/google-common': 0.0.9(zod@3.22.4) google-auth-library: 8.9.0(encoding@0.1.13) transitivePeerDependencies: @@ -19597,11 +19659,11 @@ snapshots: '@langchain/google-genai@0.0.10': dependencies: '@google/generative-ai': 0.7.0 - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 '@langchain/google-vertexai@0.0.5(encoding@0.1.13)(zod@3.22.4)': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 '@langchain/google-gauth': 0.0.5(encoding@0.1.13)(zod@3.22.4) transitivePeerDependencies: - encoding @@ -19610,17 +19672,21 @@ snapshots: '@langchain/groq@0.0.8(encoding@0.1.13)': dependencies: - '@langchain/core': 0.1.57 - '@langchain/openai': 0.0.28(encoding@0.1.13) + '@langchain/core': 0.1.63 + '@langchain/openai': 0.0.30(encoding@0.1.13) groq-sdk: 0.3.2(encoding@0.1.13) zod: 3.22.4 zod-to-json-schema: 3.22.5(zod@3.22.4) transitivePeerDependencies: - encoding + '@langchain/langgraph@0.0.12': + dependencies: + '@langchain/core': 0.1.63 + '@langchain/mistralai@0.0.19(encoding@0.1.13)': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 '@mistralai/mistralai': 0.1.3(encoding@0.1.13) uuid: 9.0.1 zod: 3.22.4 @@ -19630,7 +19696,7 @@ snapshots: '@langchain/mongodb@0.0.1(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1)': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 mongodb: 6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1) transitivePeerDependencies: - '@aws-sdk/credential-providers' @@ -19641,26 +19707,31 @@ snapshots: - snappy - socks - '@langchain/openai@0.0.28(encoding@0.1.13)': + '@langchain/openai@0.0.30(encoding@0.1.13)': dependencies: - '@langchain/core': 0.1.57 - js-tiktoken: 1.0.10 + '@langchain/core': 0.1.63 + js-tiktoken: 1.0.12 openai: 4.38.3(encoding@0.1.13) zod: 3.22.4 - zod-to-json-schema: 3.22.4(zod@3.22.4) + zod-to-json-schema: 3.22.5(zod@3.22.4) transitivePeerDependencies: - encoding '@langchain/pinecone@0.0.3': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 '@pinecone-database/pinecone': 2.2.0 flat: 5.0.2 uuid: 9.0.1 + '@langchain/textsplitters@0.0.1': + dependencies: + '@langchain/core': 0.1.63 + js-tiktoken: 1.0.12 + '@langchain/weaviate@0.0.1(encoding@0.1.13)(graphql@16.8.1)': dependencies: - '@langchain/core': 0.1.57 + '@langchain/core': 0.1.63 uuid: 9.0.1 weaviate-ts-client: 2.1.1(encoding@0.1.13)(graphql@16.8.1) transitivePeerDependencies: @@ -20228,7 +20299,7 @@ snapshots: '@opensearch-project/opensearch@1.2.0': dependencies: aws4: 1.12.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) hpagent: 0.1.2 ms: 2.1.3 secure-json-parse: 2.7.0 @@ -20245,7 +20316,7 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@pmmmwh/react-refresh-webpack-plugin@0.5.11(react-refresh@0.11.0)(type-fest@4.12.0)(webpack-dev-server@4.15.1(webpack@5.90.3(@swc/core@1.4.6)))(webpack@5.90.3(@swc/core@1.4.6))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.11(react-refresh@0.11.0)(type-fest@4.12.0)(webpack-dev-server@4.15.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)(webpack@5.90.3(@swc/core@1.4.6)))(webpack@5.90.3(@swc/core@1.4.6))': dependencies: ansi-html-community: 0.0.8 common-path-prefix: 3.0.0 @@ -20260,7 +20331,7 @@ snapshots: webpack: 5.90.3(@swc/core@1.4.6) optionalDependencies: type-fest: 4.12.0 - webpack-dev-server: 4.15.1(webpack@5.90.3(@swc/core@1.4.6)) + webpack-dev-server: 4.15.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)(webpack@5.90.3(@swc/core@1.4.6)) '@popperjs/core@2.11.8': {} @@ -20289,7 +20360,7 @@ snapshots: '@puppeteer/browsers@1.4.6(typescript@4.9.5)': dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.3.0 @@ -20874,12 +20945,12 @@ snapshots: dependencies: '@supabase/node-fetch': 2.6.15 - '@supabase/realtime-js@2.9.3': + '@supabase/realtime-js@2.9.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)': dependencies: '@supabase/node-fetch': 2.6.15 '@types/phoenix': 1.6.4 '@types/ws': 8.5.10 - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -20888,13 +20959,13 @@ snapshots: dependencies: '@supabase/node-fetch': 2.6.15 - '@supabase/supabase-js@2.39.8': + '@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4)': dependencies: '@supabase/functions-js': 2.1.5 '@supabase/gotrue-js': 2.62.2 '@supabase/node-fetch': 2.6.15 '@supabase/postgrest-js': 1.9.2 - '@supabase/realtime-js': 2.9.3 + '@supabase/realtime-js': 2.9.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@supabase/storage-js': 2.5.5 transitivePeerDependencies: - bufferutil @@ -21030,10 +21101,12 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tabler/icons@1.119.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': - optionalDependencies: + '@tabler/icons-react@3.3.0(react@18.2.0)': + dependencies: + '@tabler/icons': 3.3.0 react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + + '@tabler/icons@3.3.0': {} '@testing-library/dom@9.3.4': dependencies: @@ -21935,13 +22008,13 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color agent-base@7.1.0: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -22490,9 +22563,9 @@ snapshots: src-stream: 0.1.1 through2: 2.0.5 - assemblyai@4.3.2: + assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -22607,14 +22680,6 @@ snapshots: axe-core@4.8.4: {} - axios@1.6.2: - dependencies: - follow-redirects: 1.15.5(debug@4.3.4) - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - axios@1.6.2(debug@4.3.4): dependencies: follow-redirects: 1.15.5(debug@4.3.4) @@ -23449,6 +23514,11 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + bufferutil@4.0.8: + dependencies: + node-gyp-build: 4.8.1 + optional: true + builtin-modules@3.3.0: {} builtins@1.0.3: {} @@ -23903,7 +23973,7 @@ snapshots: cmake-js@7.3.0: dependencies: axios: 1.6.7(debug@4.3.4) - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) fs-extra: 11.2.0 lodash.isplainobject: 4.0.6 memory-stream: 1.0.0 @@ -24584,10 +24654,6 @@ snapshots: dependencies: ms: 2.0.0 - debug@3.2.7: - dependencies: - ms: 2.1.3 - debug@3.2.7(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -24600,10 +24666,6 @@ snapshots: optionalDependencies: supports-color: 8.1.1 - debug@4.3.4: - dependencies: - ms: 2.1.2 - debug@4.3.4(supports-color@5.5.0): dependencies: ms: 2.1.2 @@ -24936,6 +24998,18 @@ snapshots: readable-stream: 3.6.2 stream-shift: 1.0.3 + e2b@0.16.1: + dependencies: + isomorphic-ws: 5.0.0(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + normalize-path: 3.0.0 + openapi-typescript-fetch: 1.1.3 + path-browserify: 1.0.1 + platform: 1.3.6 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.4 + each-props@1.3.2: dependencies: is-plain-object: 2.0.4 @@ -25023,12 +25097,12 @@ snapshots: engine-utils@0.1.1: {} - engine.io-client@6.5.3: + engine.io-client@6.5.3(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: '@socket.io/component-emitter': 3.1.0 debug: 4.3.4(supports-color@5.5.0) engine.io-parser: 5.2.2 - ws: 8.11.0 + ws: 8.11.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) xmlhttprequest-ssl: 2.0.0 transitivePeerDependencies: - bufferutil @@ -25037,7 +25111,7 @@ snapshots: engine.io-parser@5.2.2: {} - engine.io@6.5.4: + engine.io@6.5.4(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 @@ -25046,9 +25120,9 @@ snapshots: base64id: 2.0.0 cookie: 0.4.2 cors: 2.8.5 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) engine.io-parser: 5.2.2 - ws: 8.11.0 + ws: 8.11.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - supports-color @@ -25305,7 +25379,7 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(eslint@8.57.0)(jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(typescript@4.9.5): + eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(eslint@8.57.0)(jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4))(typescript@4.9.5): dependencies: '@babel/core': 7.24.0 '@babel/eslint-parser': 7.23.10(@babel/core@7.24.0)(eslint@8.57.0) @@ -25317,7 +25391,7 @@ snapshots: eslint: 8.57.0 eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0) - eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(typescript@4.9.5) + eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4))(typescript@4.9.5) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.0(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) @@ -25385,13 +25459,13 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(typescript@4.9.5): + eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4))(typescript@4.9.5): dependencies: '@typescript-eslint/experimental-utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) eslint: 8.57.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.5))(eslint@8.57.0)(typescript@4.9.5) - jest: 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + jest: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) transitivePeerDependencies: - supports-color - typescript @@ -25511,7 +25585,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -25840,7 +25914,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -26144,10 +26218,10 @@ snapshots: flatted@3.3.1: {} - flowise-embed-react@1.0.2(@types/node@20.11.26)(flowise-embed@1.2.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.1)(terser@5.29.1)(typescript@4.9.5): + flowise-embed-react@1.0.2(@types/node@20.11.26)(flowise-embed@1.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.1)(terser@5.29.1)(typescript@4.9.5): dependencies: '@ladle/react': 2.5.1(@types/node@20.11.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.1)(terser@5.29.1)(typescript@4.9.5) - flowise-embed: 1.2.4 + flowise-embed: 1.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4) react: 18.2.0 transitivePeerDependencies: - '@types/node' @@ -26161,14 +26235,14 @@ snapshots: - terser - typescript - flowise-embed@1.2.4: + flowise-embed@1.2.6(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: '@babel/core': 7.24.0 '@ts-stack/markdown': 1.5.0 device-detector-js: 3.0.3 lodash: 4.17.21 prettier: 3.2.5 - socket.io-client: 4.7.4 + socket.io-client: 4.7.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) solid-element: 1.7.0(solid-js@1.7.1) solid-js: 1.7.1 zod: 3.22.4 @@ -26206,7 +26280,7 @@ snapshots: follow-redirects@1.15.5(debug@4.3.4): optionalDependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) for-each@0.3.3: dependencies: @@ -26504,7 +26578,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) fs-extra: 11.2.0 transitivePeerDependencies: - supports-color @@ -27246,7 +27320,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -27254,14 +27328,14 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -27301,14 +27375,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.4: dependencies: agent-base: 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -27459,7 +27533,7 @@ snapshots: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -27855,6 +27929,10 @@ snapshots: transitivePeerDependencies: - encoding + isomorphic-ws@5.0.0(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)): + dependencies: + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + isstream@0.1.2: {} istanbul-lib-coverage@3.2.2: {} @@ -27939,16 +28017,16 @@ snapshots: transitivePeerDependencies: - supports-color - jest-cli@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)): + jest-cli@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4): dependencies: - '@jest/core': 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + '@jest/core': 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + jest-config: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) jest-util: 27.5.1 jest-validate: 27.5.1 prompts: 2.4.2 @@ -27960,7 +28038,7 @@ snapshots: - ts-node - utf-8-validate - jest-config@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)): + jest-config@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4): dependencies: '@babel/core': 7.24.0 '@jest/test-sequencer': 27.5.1 @@ -27972,13 +28050,13 @@ snapshots: glob: 7.2.3 graceful-fs: 4.2.11 jest-circus: 27.5.1 - jest-environment-jsdom: 27.5.1(canvas@2.11.2(encoding@0.1.13)) + jest-environment-jsdom: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) jest-environment-node: 27.5.1 jest-get-type: 27.5.1 jest-jasmine2: 27.5.1 jest-regex-util: 27.5.1 jest-resolve: 27.5.1 - jest-runner: 27.5.1(canvas@2.11.2(encoding@0.1.13)) + jest-runner: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) jest-util: 27.5.1 jest-validate: 27.5.1 micromatch: 4.0.5 @@ -28020,7 +28098,7 @@ snapshots: jest-util: 27.5.1 pretty-format: 27.5.1 - jest-environment-jsdom@27.5.1(canvas@2.11.2(encoding@0.1.13)): + jest-environment-jsdom@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4): dependencies: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 @@ -28028,7 +28106,7 @@ snapshots: '@types/node': 20.11.26 jest-mock: 27.5.1 jest-util: 27.5.1 - jsdom: 16.7.0(canvas@2.11.2(encoding@0.1.13)) + jsdom: 16.7.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - canvas @@ -28176,7 +28254,7 @@ snapshots: resolve.exports: 1.1.1 slash: 3.0.0 - jest-runner@27.5.1(canvas@2.11.2(encoding@0.1.13)): + jest-runner@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4): dependencies: '@jest/console': 27.5.1 '@jest/environment': 27.5.1 @@ -28188,7 +28266,7 @@ snapshots: emittery: 0.8.1 graceful-fs: 4.2.11 jest-docblock: 27.5.1 - jest-environment-jsdom: 27.5.1(canvas@2.11.2(encoding@0.1.13)) + jest-environment-jsdom: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) jest-environment-node: 27.5.1 jest-haste-map: 27.5.1 jest-leak-detector: 27.5.1 @@ -28300,11 +28378,11 @@ snapshots: leven: 3.1.0 pretty-format: 27.5.1 - jest-watch-typeahead@1.1.0(jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))): + jest-watch-typeahead@1.1.0(jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4)): dependencies: ansi-escapes: 4.3.2 chalk: 4.1.2 - jest: 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + jest: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) jest-regex-util: 28.0.2 jest-watcher: 28.1.3 slash: 4.0.0 @@ -28350,11 +28428,11 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)): + jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4): dependencies: - '@jest/core': 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + '@jest/core': 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) import-local: 3.1.0 - jest-cli: 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + jest-cli: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - canvas @@ -28382,6 +28460,10 @@ snapshots: dependencies: base64-js: 1.5.1 + js-tiktoken@1.0.12: + dependencies: + base64-js: 1.5.1 + js-tokens@3.0.2: {} js-tokens@4.0.0: {} @@ -28421,7 +28503,7 @@ snapshots: strip-json-comments: 3.1.1 underscore: 1.13.6 - jsdom@16.7.0(canvas@2.11.2(encoding@0.1.13)): + jsdom@16.7.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4): dependencies: abab: 2.0.6 acorn: 8.11.3 @@ -28448,7 +28530,7 @@ snapshots: whatwg-encoding: 1.0.5 whatwg-mimetype: 2.3.0 whatwg-url: 8.7.0 - ws: 7.5.9 + ws: 7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.4) xml-name-validator: 3.0.0 optionalDependencies: canvas: 2.11.2(encoding@0.1.13) @@ -28457,7 +28539,7 @@ snapshots: - supports-color - utf-8-validate - jsdom@20.0.3(canvas@2.11.2(encoding@0.1.13)): + jsdom@20.0.3(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4): dependencies: abab: 2.0.6 acorn: 8.11.3 @@ -28483,7 +28565,7 @@ snapshots: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) xml-name-validator: 4.0.0 optionalDependencies: canvas: 2.11.2(encoding@0.1.13) @@ -28492,7 +28574,7 @@ snapshots: - supports-color - utf-8-validate - jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)): + jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4): dependencies: abab: 2.0.6 cssstyle: 3.0.0 @@ -28515,7 +28597,7 @@ snapshots: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 12.0.1 - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) xml-name-validator: 4.0.0 optionalDependencies: canvas: 2.11.2(encoding@0.1.13) @@ -28669,12 +28751,13 @@ snapshots: kuler@2.0.0: {} - langchain@0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0): + langchain@0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)): dependencies: '@anthropic-ai/sdk': 0.9.1(encoding@0.1.13) - '@langchain/community': 0.0.48(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0) - '@langchain/core': 0.1.57 - '@langchain/openai': 0.0.28(encoding@0.1.13) + '@langchain/community': 0.0.48(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(encoding@0.1.13)(faiss-node@0.5.1)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(portkey-ai@0.1.16)(redis@4.6.13)(replicate@0.18.1)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@langchain/core': 0.1.63 + '@langchain/openai': 0.0.30(encoding@0.1.13) + '@langchain/textsplitters': 0.0.1 binary-extensions: 2.2.0 js-tiktoken: 1.0.10 js-yaml: 4.1.0 @@ -28687,7 +28770,7 @@ snapshots: uuid: 9.0.1 yaml: 2.4.1 zod: 3.22.4 - zod-to-json-schema: 3.22.4(zod@3.22.4) + zod-to-json-schema: 3.22.5(zod@3.22.4) optionalDependencies: '@aws-sdk/client-s3': 3.529.1 '@aws-sdk/credential-provider-node': 3.529.1 @@ -28696,10 +28779,10 @@ snapshots: '@google-ai/generativelanguage': 0.2.1(encoding@0.1.13) '@notionhq/client': 2.2.14(encoding@0.1.13) '@pinecone-database/pinecone': 2.2.0 - '@supabase/supabase-js': 2.39.8 + '@supabase/supabase-js': 2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4) apify-client: 2.9.3 - assemblyai: 4.3.2 - axios: 1.6.2 + assemblyai: 4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + axios: 1.6.2(debug@4.3.4) cheerio: 1.0.0-rc.12 chromadb: 1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)) couchbase: 4.3.1 @@ -28710,19 +28793,19 @@ snapshots: html-to-text: 9.0.5 ignore: 5.3.1 ioredis: 5.3.2 - jsdom: 22.1.0(canvas@2.11.2(encoding@0.1.13)) + jsdom: 22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) mammoth: 1.7.0 mongodb: 6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1) notion-to-md: 3.1.1(encoding@0.1.13) pdf-parse: 1.1.1 playwright: 1.42.1 - puppeteer: 20.9.0(encoding@0.1.13)(typescript@4.9.5) - pyodide: 0.25.0 + puppeteer: 20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4) + pyodide: 0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) redis: 4.6.13 srt-parser-2: 1.2.3 typeorm: 0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) weaviate-ts-client: 1.6.0(encoding@0.1.13)(graphql@16.8.1) - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - '@aws-crypto/sha256-js' - '@aws-sdk/client-bedrock-agent-runtime' @@ -28798,9 +28881,9 @@ snapshots: dependencies: mustache: 4.2.0 - langfuse-langchain@3.3.4(langchain@0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0)): + langfuse-langchain@3.3.4(langchain@0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))): dependencies: - langchain: 0.1.33(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8)(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2)(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(canvas@2.11.2(encoding@0.1.13)))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5))(pyodide@0.25.0)(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0) + langchain: 0.1.37(@aws-crypto/sha256-js@5.2.0)(@aws-sdk/client-bedrock-runtime@3.422.0)(@aws-sdk/client-dynamodb@3.529.1)(@aws-sdk/client-s3@3.529.1)(@aws-sdk/credential-provider-node@3.529.1)(@datastax/astra-db-ts@0.1.4)(@elastic/elasticsearch@8.12.2)(@getzep/zep-js@0.9.0)(@gomomento/sdk-core@1.68.1)(@gomomento/sdk@1.68.1(encoding@0.1.13))(@google-ai/generativelanguage@0.2.1(encoding@0.1.13))(@huggingface/inference@2.6.4)(@notionhq/client@2.2.14(encoding@0.1.13))(@opensearch-project/opensearch@1.2.0)(@pinecone-database/pinecone@2.2.0)(@qdrant/js-client-rest@1.8.1(typescript@4.9.5))(@smithy/eventstream-codec@2.1.4)(@smithy/protocol-http@3.2.2)(@smithy/signature-v4@2.1.4)(@smithy/util-utf8@2.2.0)(@supabase/postgrest-js@1.9.2)(@supabase/supabase-js@2.39.8(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@upstash/redis@1.22.1(encoding@0.1.13))(@upstash/vector@1.0.7)(@xenova/transformers@2.16.0)(@zilliz/milvus2-sdk-node@2.3.5)(apify-client@2.9.3)(assemblyai@4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))(axios@1.6.2)(cheerio@1.0.0-rc.12)(chromadb@1.8.1(@google/generative-ai@0.7.0)(cohere-ai@6.2.2)(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)))(cohere-ai@6.2.2)(couchbase@4.3.1)(d3-dsv@2.0.0)(encoding@0.1.13)(faiss-node@0.5.1)(fast-xml-parser@4.3.5)(google-auth-library@9.6.3(encoding@0.1.13))(html-to-text@9.0.5)(ignore@5.3.1)(ioredis@5.3.2)(jsdom@22.1.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4))(lodash@4.17.21)(lunary@0.6.16(openai@4.38.3(encoding@0.1.13))(react@18.2.0))(mammoth@1.7.0)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(notion-to-md@3.1.1(encoding@0.1.13))(pdf-parse@1.1.1)(pg@8.11.3)(playwright@1.42.1)(portkey-ai@0.1.16)(puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4))(pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(redis@4.6.13)(replicate@0.18.1)(srt-parser-2@1.2.3)(typeorm@0.3.20(ioredis@5.3.2)(mongodb@6.3.0(gcp-metadata@6.1.0(encoding@0.1.13))(socks@2.8.1))(mysql2@3.9.2)(pg@8.11.3)(redis@4.6.13)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(weaviate-ts-client@1.6.0(encoding@0.1.13)(graphql@16.8.1))(ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) langfuse: 3.3.4 langfuse-core: 3.3.4 @@ -28952,7 +29035,7 @@ snapshots: optionalDependencies: enquirer: 2.4.1 - llamaindex@0.2.1(@google/generative-ai@0.7.0)(encoding@0.1.13)(gcp-metadata@6.1.0(encoding@0.1.13))(node-fetch@2.7.0(encoding@0.1.13))(socks@2.8.1)(typescript@4.9.5): + llamaindex@0.2.1(@google/generative-ai@0.7.0)(bufferutil@4.0.8)(encoding@0.1.13)(gcp-metadata@6.1.0(encoding@0.1.13))(node-fetch@2.7.0(encoding@0.1.13))(socks@2.8.1)(typescript@4.9.5)(utf-8-validate@6.0.4): dependencies: '@anthropic-ai/sdk': 0.18.0(encoding@0.1.13) '@aws-crypto/sha256-js': 5.2.0 @@ -28970,7 +29053,7 @@ snapshots: '@types/pg': 8.11.2 '@xenova/transformers': 2.16.0 '@zilliz/milvus2-sdk-node': 2.3.5 - assemblyai: 4.3.2 + assemblyai: 4.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) chromadb: 1.7.3(@google/generative-ai@0.7.0)(cohere-ai@7.7.7(encoding@0.1.13))(encoding@0.1.13)(openai@4.38.3(encoding@0.1.13)) cohere-ai: 7.7.7(encoding@0.1.13) js-tiktoken: 1.0.10 @@ -29966,7 +30049,7 @@ snapshots: micromark@2.11.4: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) parse-entities: 2.0.0 transitivePeerDependencies: - supports-color @@ -30349,6 +30432,9 @@ snapshots: node-forge@1.3.1: {} + node-gyp-build@4.8.1: + optional: true + node-gyp@8.4.1: dependencies: env-paths: 2.2.1 @@ -30851,6 +30937,8 @@ snapshots: openapi-types@12.1.3: {} + openapi-typescript-fetch@1.1.3: {} + option-cache@3.5.0: dependencies: arr-flatten: 1.1.0 @@ -30977,7 +31065,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) get-uri: 6.0.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.4 @@ -31177,6 +31265,8 @@ snapshots: ansi-escapes: 4.3.2 cross-spawn: 7.0.3 + path-browserify@1.0.1: {} + path-dirname@1.0.2: {} path-exists@2.1.0: @@ -31233,7 +31323,7 @@ snapshots: pdf-parse@1.1.1: dependencies: - debug: 3.2.7 + debug: 3.2.7(supports-color@5.5.0) node-ensure: 0.0.0 transitivePeerDependencies: - supports-color @@ -32059,7 +32149,7 @@ snapshots: proxy-agent@6.3.0: dependencies: agent-base: 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.4 lru-cache: 7.18.3 @@ -32103,14 +32193,14 @@ snapshots: punycode@2.3.1: {} - puppeteer-core@20.9.0(encoding@0.1.13)(typescript@4.9.5): + puppeteer-core@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4): dependencies: '@puppeteer/browsers': 1.4.6(typescript@4.9.5) chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) cross-fetch: 4.0.0(encoding@0.1.13) - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) devtools-protocol: 0.0.1147663 - ws: 8.13.0 + ws: 8.13.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) optionalDependencies: typescript: 4.9.5 transitivePeerDependencies: @@ -32119,11 +32209,11 @@ snapshots: - supports-color - utf-8-validate - puppeteer@20.9.0(encoding@0.1.13)(typescript@4.9.5): + puppeteer@20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4): dependencies: '@puppeteer/browsers': 1.4.6(typescript@4.9.5) cosmiconfig: 8.2.0 - puppeteer-core: 20.9.0(encoding@0.1.13)(typescript@4.9.5) + puppeteer-core: 20.9.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@4.9.5)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - encoding @@ -32133,10 +32223,10 @@ snapshots: pure-color@1.3.0: {} - pyodide@0.25.0: + pyodide@0.25.0(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: base-64: 1.0.0 - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -32480,10 +32570,10 @@ snapshots: history: 5.3.0 react: 18.2.0 - react-scripts@5.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(@swc/core@1.4.6)(@types/babel__core@7.20.5)(canvas@2.11.2(encoding@0.1.13))(eslint@8.57.0)(react@18.2.0)(sass@1.71.1)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(type-fest@4.12.0)(typescript@4.9.5): + react-scripts@5.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(@swc/core@1.4.6)(@types/babel__core@7.20.5)(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(eslint@8.57.0)(react@18.2.0)(sass@1.71.1)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(type-fest@4.12.0)(typescript@4.9.5)(utf-8-validate@6.0.4): dependencies: '@babel/core': 7.24.0 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.11(react-refresh@0.11.0)(type-fest@4.12.0)(webpack-dev-server@4.15.1(webpack@5.90.3(@swc/core@1.4.6)))(webpack@5.90.3(@swc/core@1.4.6)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.11(react-refresh@0.11.0)(type-fest@4.12.0)(webpack-dev-server@4.15.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)(webpack@5.90.3(@swc/core@1.4.6)))(webpack@5.90.3(@swc/core@1.4.6)) '@svgr/webpack': 5.5.0 babel-jest: 27.5.1(@babel/core@7.24.0) babel-loader: 8.3.0(@babel/core@7.24.0)(webpack@5.90.3(@swc/core@1.4.6)) @@ -32498,15 +32588,15 @@ snapshots: dotenv: 10.0.0 dotenv-expand: 5.1.0 eslint: 8.57.0 - eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(eslint@8.57.0)(jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)))(typescript@4.9.5) + eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0))(@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.0))(eslint@8.57.0)(jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4))(typescript@4.9.5) eslint-webpack-plugin: 3.2.0(eslint@8.57.0)(webpack@5.90.3(@swc/core@1.4.6)) file-loader: 6.2.0(webpack@5.90.3(@swc/core@1.4.6)) fs-extra: 10.1.0 html-webpack-plugin: 5.6.0(webpack@5.90.3(@swc/core@1.4.6)) identity-obj-proxy: 3.0.0 - jest: 27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) + jest: 27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4) jest-resolve: 27.5.1 - jest-watch-typeahead: 1.1.0(jest@27.5.1(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))) + jest-watch-typeahead: 1.1.0(jest@27.5.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5))(utf-8-validate@6.0.4)) mini-css-extract-plugin: 2.8.1(webpack@5.90.3(@swc/core@1.4.6)) postcss: 8.4.35 postcss-flexbugs-fixes: 5.0.2(postcss@8.4.35) @@ -32527,7 +32617,7 @@ snapshots: tailwindcss: 3.4.1(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@20.11.26)(typescript@4.9.5)) terser-webpack-plugin: 5.3.10(@swc/core@1.4.6)(webpack@5.90.3(@swc/core@1.4.6)) webpack: 5.90.3(@swc/core@1.4.6) - webpack-dev-server: 4.15.1(webpack@5.90.3(@swc/core@1.4.6)) + webpack-dev-server: 4.15.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)(webpack@5.90.3(@swc/core@1.4.6)) webpack-manifest-plugin: 4.1.1(webpack@5.90.3(@swc/core@1.4.6)) workbox-webpack-plugin: 6.6.0(@types/babel__core@7.20.5)(webpack@5.90.3(@swc/core@1.4.6)) optionalDependencies: @@ -32844,13 +32934,13 @@ snapshots: dependencies: jsesc: 0.5.0 - rehype-mathjax@4.0.3(canvas@2.11.2(encoding@0.1.13)): + rehype-mathjax@4.0.3(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4): dependencies: '@types/hast': 2.3.10 '@types/mathjax': 0.0.37 hast-util-from-dom: 4.2.0 hast-util-to-text: 3.1.2 - jsdom: 20.0.3(canvas@2.11.2(encoding@0.1.13)) + jsdom: 20.0.3(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.4) mathjax-full: 3.2.2 unified: 10.1.2 unist-util-visit: 4.1.2 @@ -33094,7 +33184,7 @@ snapshots: retry-request@5.0.2: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) extend: 3.0.2 transitivePeerDependencies: - supports-color @@ -33561,20 +33651,20 @@ snapshots: transitivePeerDependencies: - supports-color - socket.io-adapter@2.5.4: + socket.io-adapter@2.5.4(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: - debug: 4.3.4 - ws: 8.11.0 + debug: 4.3.4(supports-color@5.5.0) + ws: 8.11.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - socket.io-client@4.7.4: + socket.io-client@4.7.4(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: '@socket.io/component-emitter': 3.1.0 debug: 4.3.4(supports-color@5.5.0) - engine.io-client: 6.5.3 + engine.io-client: 6.5.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) socket.io-parser: 4.2.4 transitivePeerDependencies: - bufferutil @@ -33584,18 +33674,18 @@ snapshots: socket.io-parser@4.2.4: dependencies: '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color - socket.io@4.7.4: + socket.io@4.7.4(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.5 - debug: 4.3.4 - engine.io: 6.5.4 - socket.io-adapter: 2.5.4 + debug: 4.3.4(supports-color@5.5.0) + engine.io: 6.5.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) + socket.io-adapter: 2.5.4(bufferutil@4.0.8)(utf-8-validate@6.0.4) socket.io-parser: 4.2.4 transitivePeerDependencies: - bufferutil @@ -33611,7 +33701,7 @@ snapshots: socks-proxy-agent@6.2.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) socks: 2.8.1 transitivePeerDependencies: - supports-color @@ -33619,7 +33709,7 @@ snapshots: socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) socks: 2.8.1 transitivePeerDependencies: - supports-color @@ -33627,7 +33717,7 @@ snapshots: socks-proxy-agent@8.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) socks: 2.8.1 transitivePeerDependencies: - supports-color @@ -34670,7 +34760,7 @@ snapshots: chalk: 4.1.2 cli-highlight: 2.1.11 dayjs: 1.11.10 - debug: 4.3.4 + debug: 4.3.4(supports-color@5.5.0) dotenv: 16.4.5 glob: 10.3.10 mkdirp: 2.1.6 @@ -35002,6 +35092,11 @@ snapshots: use@3.1.1: {} + utf-8-validate@6.0.4: + dependencies: + node-gyp-build: 4.8.1 + optional: true + util-deprecate@1.0.2: {} util.promisify@1.0.1: @@ -35348,7 +35443,7 @@ snapshots: schema-utils: 4.2.0 webpack: 5.90.3(@swc/core@1.4.6) - webpack-dev-server@4.15.1(webpack@5.90.3(@swc/core@1.4.6)): + webpack-dev-server@4.15.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)(webpack@5.90.3(@swc/core@1.4.6)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -35379,7 +35474,7 @@ snapshots: sockjs: 0.3.24 spdy: 4.0.2 webpack-dev-middleware: 5.3.3(webpack@5.90.3(@swc/core@1.4.6)) - ws: 8.16.0 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) optionalDependencies: webpack: 5.90.3(@swc/core@1.4.6) transitivePeerDependencies: @@ -35873,13 +35968,25 @@ snapshots: dependencies: mkdirp: 0.5.6 - ws@7.5.9: {} + ws@7.5.9(bufferutil@4.0.8)(utf-8-validate@6.0.4): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.4 - ws@8.11.0: {} + ws@8.11.0(bufferutil@4.0.8)(utf-8-validate@6.0.4): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.4 - ws@8.13.0: {} + ws@8.13.0(bufferutil@4.0.8)(utf-8-validate@6.0.4): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.4 - ws@8.16.0: {} + ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 6.0.4 xdg-default-browser@2.1.0: dependencies: