From 3fb800190778a67deb46928708ad8e8773154fd3 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sat, 30 Dec 2023 14:13:39 -0500 Subject: [PATCH 01/40] Added support to exclude specific Airtable Field Ids --- .../documentloaders/Airtable/Airtable.ts | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index a2c1eef3f..dfa059838 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -64,6 +64,16 @@ class Airtable_DocumentLoaders implements INode { 'If your view URL looks like: https://airtable.com/app11RobdGoX0YNsC/tblJdmvbrgizbYICO/viw9UrP77Id0CE4ee, viw9UrP77Id0CE4ee is the view id', optional: true }, + { + label: 'Exclude Field Ids', + name: 'excludeFieldIds', + type: 'string', + placeholder: 'fld1u0qUz0SoOQ9Gg, fldAMOvPfwxr12VrK', + optional: true, + additionalParams: true, + description: + 'Comma-separated list of field ids to exclude' + }, { label: 'Return All', name: 'returnAll', @@ -93,6 +103,7 @@ class Airtable_DocumentLoaders implements INode { const baseId = nodeData.inputs?.baseId as string const tableId = nodeData.inputs?.tableId as string const viewId = nodeData.inputs?.viewId as string + const excludeFieldIds = nodeData.inputs?.excludeFieldIds as string const returnAll = nodeData.inputs?.returnAll as boolean const limit = nodeData.inputs?.limit as string const textSplitter = nodeData.inputs?.textSplitter as TextSplitter @@ -105,6 +116,7 @@ class Airtable_DocumentLoaders implements INode { baseId, tableId, viewId, + excludeFieldIds: excludeFieldIds ? excludeFieldIds.split(',').map(id => id.trim()) : [], returnAll, accessToken, limit: limit ? parseInt(limit, 10) : 100 @@ -145,6 +157,7 @@ interface AirtableLoaderParams { tableId: string accessToken: string viewId?: string + excludeFieldIds?: string[] limit?: number returnAll?: boolean } @@ -167,17 +180,20 @@ class AirtableLoader extends BaseDocumentLoader { public readonly viewId?: string + public readonly excludeFieldIds: string[] + public readonly accessToken: string public readonly limit: number public readonly returnAll: boolean - constructor({ baseId, tableId, viewId, accessToken, limit = 100, returnAll = false }: AirtableLoaderParams) { + constructor({ baseId, tableId, viewId, excludeFieldIds = [], accessToken, limit = 100, returnAll = false }: AirtableLoaderParams) { super() this.baseId = baseId this.tableId = tableId this.viewId = viewId + this.excludeFieldIds = excludeFieldIds this.accessToken = accessToken this.limit = limit this.returnAll = returnAll @@ -207,10 +223,16 @@ class AirtableLoader extends BaseDocumentLoader { private createDocumentFromPage(page: AirtableLoaderPage): Document { // Generate the URL const pageUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}/${page.id}` + const fields = { ...page.fields }; + + // Exclude any specified fields + this.excludeFieldIds.forEach(id => { + delete fields[id]; + }); // Return a langchain document return new Document({ - pageContent: JSON.stringify(page.fields, null, 2), + pageContent: JSON.stringify(fields, null, 2), metadata: { url: pageUrl } From 6006157958f21347c6feff68ca56a313e813712b Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sat, 30 Dec 2023 15:17:33 -0500 Subject: [PATCH 02/40] Updated Airtable field exclusion support to use field names instead of field ids --- .../documentloaders/Airtable/Airtable.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index dfa059838..d7ae26675 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -65,14 +65,14 @@ class Airtable_DocumentLoaders implements INode { optional: true }, { - label: 'Exclude Field Ids', - name: 'excludeFieldIds', + label: 'Exclude Field Names', + name: 'excludeFieldNames', type: 'string', - placeholder: 'fld1u0qUz0SoOQ9Gg, fldAMOvPfwxr12VrK', + placeholder: 'Name, Assignee', optional: true, additionalParams: true, description: - 'Comma-separated list of field ids to exclude' + 'Comma-separated list of field names to exclude' }, { label: 'Return All', @@ -103,7 +103,7 @@ class Airtable_DocumentLoaders implements INode { const baseId = nodeData.inputs?.baseId as string const tableId = nodeData.inputs?.tableId as string const viewId = nodeData.inputs?.viewId as string - const excludeFieldIds = nodeData.inputs?.excludeFieldIds as string + const excludeFieldNames = nodeData.inputs?.excludeFieldNames as string const returnAll = nodeData.inputs?.returnAll as boolean const limit = nodeData.inputs?.limit as string const textSplitter = nodeData.inputs?.textSplitter as TextSplitter @@ -116,7 +116,7 @@ class Airtable_DocumentLoaders implements INode { baseId, tableId, viewId, - excludeFieldIds: excludeFieldIds ? excludeFieldIds.split(',').map(id => id.trim()) : [], + excludeFieldNames: excludeFieldNames ? excludeFieldNames.split(',').map(id => id.trim()) : [], returnAll, accessToken, limit: limit ? parseInt(limit, 10) : 100 @@ -157,7 +157,7 @@ interface AirtableLoaderParams { tableId: string accessToken: string viewId?: string - excludeFieldIds?: string[] + excludeFieldNames?: string[] limit?: number returnAll?: boolean } @@ -180,7 +180,7 @@ class AirtableLoader extends BaseDocumentLoader { public readonly viewId?: string - public readonly excludeFieldIds: string[] + public readonly excludeFieldNames: string[] public readonly accessToken: string @@ -188,12 +188,12 @@ class AirtableLoader extends BaseDocumentLoader { public readonly returnAll: boolean - constructor({ baseId, tableId, viewId, excludeFieldIds = [], accessToken, limit = 100, returnAll = false }: AirtableLoaderParams) { + constructor({ baseId, tableId, viewId, excludeFieldNames = [], accessToken, limit = 100, returnAll = false }: AirtableLoaderParams) { super() this.baseId = baseId this.tableId = tableId this.viewId = viewId - this.excludeFieldIds = excludeFieldIds + this.excludeFieldNames = excludeFieldNames this.accessToken = accessToken this.limit = limit this.returnAll = returnAll @@ -226,7 +226,7 @@ class AirtableLoader extends BaseDocumentLoader { const fields = { ...page.fields }; // Exclude any specified fields - this.excludeFieldIds.forEach(id => { + this.excludeFieldNames.forEach(id => { delete fields[id]; }); From e88859f5d4326a44743e0a87e871e31ca9e00c7d Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Mon, 1 Jan 2024 13:33:09 -0500 Subject: [PATCH 03/40] Added support for gpt-4 and gpt-4-32k models --- .../components/nodes/llms/Azure OpenAI/AzureOpenAI.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts index f50e3d95d..a8ac88307 100644 --- a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts +++ b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts @@ -18,7 +18,7 @@ class AzureOpenAI_LLMs implements INode { constructor() { this.label = 'Azure OpenAI' this.name = 'azureOpenAI' - this.version = 2.0 + this.version = 2.1 this.type = 'AzureOpenAI' this.icon = 'Azure.svg' this.category = 'LLMs' @@ -89,6 +89,14 @@ class AzureOpenAI_LLMs implements INode { { label: 'gpt-35-turbo', name: 'gpt-35-turbo' + }, + { + label: 'gpt-4', + name: 'gpt-4' + }, + { + label: 'gpt-4-32k', + name: 'gpt-4-32k' } ], default: 'text-davinci-003', From 66701cec8a8def398813f584663ab83b3cb13a26 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Wed, 3 Jan 2024 13:35:25 -0500 Subject: [PATCH 04/40] Fixing linting issues using 'yarn lint-fix' --- .../documentloaders/Airtable/Airtable.ts | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index d7ae26675..04d7d7358 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -55,24 +55,23 @@ class Airtable_DocumentLoaders implements INode { description: 'If your table URL looks like: https://airtable.com/app11RobdGoX0YNsC/tblJdmvbrgizbYICO/viw9UrP77Id0CE4ee, tblJdmvbrgizbYICO is the table id' }, - { - label: 'View Id', - name: 'viewId', - type: 'string', - placeholder: 'viw9UrP77Id0CE4ee', - description: - 'If your view URL looks like: https://airtable.com/app11RobdGoX0YNsC/tblJdmvbrgizbYICO/viw9UrP77Id0CE4ee, viw9UrP77Id0CE4ee is the view id', - optional: true + { + label: 'View Id', + name: 'viewId', + type: 'string', + placeholder: 'viw9UrP77Id0CE4ee', + description: + 'If your view URL looks like: https://airtable.com/app11RobdGoX0YNsC/tblJdmvbrgizbYICO/viw9UrP77Id0CE4ee, viw9UrP77Id0CE4ee is the view id', + optional: true }, { - label: 'Exclude Field Names', - name: 'excludeFieldNames', - type: 'string', - placeholder: 'Name, Assignee', - optional: true, + label: 'Exclude Field Names', + name: 'excludeFieldNames', + type: 'string', + placeholder: 'Name, Assignee', + optional: true, additionalParams: true, - description: - 'Comma-separated list of field names to exclude' + description: 'Comma-separated list of field names to exclude' }, { label: 'Return All', @@ -116,7 +115,7 @@ class Airtable_DocumentLoaders implements INode { baseId, tableId, viewId, - excludeFieldNames: excludeFieldNames ? excludeFieldNames.split(',').map(id => id.trim()) : [], + excludeFieldNames: excludeFieldNames ? excludeFieldNames.split(',').map((id) => id.trim()) : [], returnAll, accessToken, limit: limit ? parseInt(limit, 10) : 100 @@ -223,12 +222,12 @@ class AirtableLoader extends BaseDocumentLoader { private createDocumentFromPage(page: AirtableLoaderPage): Document { // Generate the URL const pageUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}/${page.id}` - const fields = { ...page.fields }; + const fields = { ...page.fields } // Exclude any specified fields - this.excludeFieldNames.forEach(id => { - delete fields[id]; - }); + this.excludeFieldNames.forEach((id) => { + delete fields[id] + }) // Return a langchain document return new Document({ From e8c85035f238cdacd3f23e148914d49502aff753 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Wed, 3 Jan 2024 15:25:00 -0500 Subject: [PATCH 05/40] Made streaming support a configurable option within the AzureChatOpenAI node --- .../chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index 9b7b724a2..33f6b76ef 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -19,7 +19,7 @@ class AzureChatOpenAI_ChatModels implements INode { constructor() { this.label = 'Azure ChatOpenAI' this.name = 'azureChatOpenAI' - this.version = 2.0 + this.version = 2.1 this.type = 'AzureChatOpenAI' this.icon = 'Azure.svg' this.category = 'Chat Models' @@ -102,6 +102,14 @@ class AzureChatOpenAI_ChatModels implements INode { step: 1, optional: true, additionalParams: true + }, + { + label: 'Streaming', + name: 'streaming', + type: 'boolean', + default: true, + optional: true, + additionalParams: true } ] } From e3982476b0064bbc4bfe42af0cd06500a1095751 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Thu, 4 Jan 2024 12:07:25 -0500 Subject: [PATCH 06/40] Bumping version --- packages/components/nodes/documentloaders/Airtable/Airtable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 04d7d7358..0f212a0a8 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -20,7 +20,7 @@ class Airtable_DocumentLoaders implements INode { constructor() { this.label = 'Airtable' this.name = 'airtable' - this.version = 1.0 + this.version = 2.0 this.type = 'Document' this.icon = 'airtable.svg' this.category = 'Document Loaders' From 3d2b4077cfd5231e908bc279e0bba5fd9e995056 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Thu, 4 Jan 2024 12:09:08 -0500 Subject: [PATCH 07/40] Removed streaming feature since it broke chatflows --- .../nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index 33f6b76ef..a459a8ec3 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -102,14 +102,6 @@ class AzureChatOpenAI_ChatModels implements INode { step: 1, optional: true, additionalParams: true - }, - { - label: 'Streaming', - name: 'streaming', - type: 'boolean', - default: true, - optional: true, - additionalParams: true } ] } From 3be2393412fd0866b9f3bb0759ffeaff69253311 Mon Sep 17 00:00:00 2001 From: automaton82 Date: Thu, 25 Jan 2024 11:39:13 -0500 Subject: [PATCH 08/40] Implementing CORS and CSP headers from env config --- packages/server/.env.example | 2 ++ packages/server/src/index.ts | 37 ++++++++++++++++++++++++++++---- packages/server/src/utils/XSS.ts | 11 ++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/server/.env.example b/packages/server/.env.example index ed54ac66a..8b5dbe8fc 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -1,4 +1,6 @@ PORT=3000 +# CORS_ORIGINS="*" +# EMBEDDING_ORIGINS="*" # DATABASE_PATH=/your_database_path/.flowise # APIKEY_PATH=/your_api_key_path/.flowise # SECRETKEY_PATH=/your_api_key_path/.flowise diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 6d4c18870..14685aee7 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -62,7 +62,7 @@ import { CachePool } from './CachePool' import { ICommonObject, IMessage, INodeOptionsValue, handleEscapeCharacters } from 'flowise-components' import { createRateLimiter, getRateLimiter, initializeRateLimiter } from './utils/rateLimit' import { addAPIKey, compareKeys, deleteAPIKey, getApiKey, getAPIKeys, updateAPIKey } from './utils/apiKey' -import { sanitizeMiddleware } from './utils/XSS' +import { sanitizeMiddleware, getAllowedCorsOrigins, getAllowedEmbeddingOrigins } from './utils/XSS' import axios from 'axios' import { Client } from 'langchainhub' import { parsePrompt } from './utils/hub' @@ -126,8 +126,30 @@ export class App { if (process.env.NUMBER_OF_PROXIES && parseInt(process.env.NUMBER_OF_PROXIES) > 0) this.app.set('trust proxy', parseInt(process.env.NUMBER_OF_PROXIES)) - // Allow access from * - this.app.use(cors()) + // Allow access from specified domains + const corsOptions = { + origin: function (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) { + const allowedOrigins = getAllowedCorsOrigins() + if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { + callback(null, true) + } else { + callback(new Error('Not allowed by CORS')) + } + } + } + this.app.use(cors(corsOptions)) + + // Allow embedding from specified domains. + this.app.use((req, res, next) => { + const allowedOrigins = getAllowedEmbeddingOrigins() + if (allowedOrigins == '*') { + next() + } else { + const csp = `frame-ancestors ${allowedOrigins}` + res.setHeader('Content-Security-Policy', csp) + next() + } + }) // Switch off the default 'X-Powered-By: Express' header this.app.disable('x-powered-by') @@ -1863,7 +1885,14 @@ export async function start(): Promise { const io = new Server(server, { cors: { - origin: '*' + origin: function (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) { + const allowedOrigins = getAllowedCorsOrigins() + if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { + callback(null, true) + } else { + callback(new Error('Not allowed by CORS')) + } + } } }) diff --git a/packages/server/src/utils/XSS.ts b/packages/server/src/utils/XSS.ts index 5d8b81e91..a9ad92786 100644 --- a/packages/server/src/utils/XSS.ts +++ b/packages/server/src/utils/XSS.ts @@ -18,3 +18,14 @@ export function sanitizeMiddleware(req: Request, res: Response, next: NextFuncti } next() } + +export function getAllowedCorsOrigins(): string { + // Expects FQDN separated by commas, otherwise nothing or * for all. + return process.env.CORS_ORIGINS ?? '*' +} + +export function getAllowedEmbeddingOrigins(): string { + // Expects FQDN separated by commas, otherwise nothing or * for all. + // Also CSP allowed values: self or none + return process.env.EMBEDDING_ORIGINS ?? '*' +} From 657dace89e9d7b6089de6f01e76608724e4aac4a Mon Sep 17 00:00:00 2001 From: automaton82 Date: Thu, 25 Jan 2024 15:29:02 -0500 Subject: [PATCH 09/40] Fixing comments from PR --- CONTRIBUTING.md | 2 ++ docker/.env.example | 3 +++ docker/docker-compose.yml | 2 ++ packages/server/.env.example | 2 +- packages/server/src/commands/start.ts | 4 ++++ packages/server/src/index.ts | 27 ++++----------------------- packages/server/src/utils/XSS.ts | 18 ++++++++++++++++-- 7 files changed, 32 insertions(+), 26 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 88d1aaacd..747c0f396 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -123,6 +123,8 @@ Flowise support different environment variables to configure your instance. You | Variable | Description | Type | Default | | --------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- | | PORT | The HTTP port Flowise runs on | Number | 3000 | +| CORS_ORIGINS | The allowed origins for all cross-origin HTTP calls | String | | +| IFRAME_ORIGINS | The allowed origins for iframe src embedding | String | | | FLOWISE_USERNAME | Username to login | String | | | FLOWISE_PASSWORD | Password to login | String | | | DEBUG | Print logs from components | Boolean | | diff --git a/docker/.env.example b/docker/.env.example index 0fe69dd1f..318ce8647 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -4,6 +4,9 @@ APIKEY_PATH=/root/.flowise SECRETKEY_PATH=/root/.flowise LOG_PATH=/root/.flowise/logs +# CORS_ORIGINS="*" +# IFRAME_ORIGINS="*" + # NUMBER_OF_PROXIES= 1 # DATABASE_TYPE=postgres diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index c8c88bf37..24cbb22e2 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -6,6 +6,8 @@ services: restart: always environment: - PORT=${PORT} + - CORS_ORIGINS=${CORS_ORIGINS} + - IFRAME_ORIGINS=${IFRAME_ORIGINS} - FLOWISE_USERNAME=${FLOWISE_USERNAME} - FLOWISE_PASSWORD=${FLOWISE_PASSWORD} - DEBUG=${DEBUG} diff --git a/packages/server/.env.example b/packages/server/.env.example index 8b5dbe8fc..5f1b18480 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -1,6 +1,6 @@ PORT=3000 # CORS_ORIGINS="*" -# EMBEDDING_ORIGINS="*" +# IFRAME_ORIGINS="*" # DATABASE_PATH=/your_database_path/.flowise # APIKEY_PATH=/your_api_key_path/.flowise # SECRETKEY_PATH=/your_api_key_path/.flowise diff --git a/packages/server/src/commands/start.ts b/packages/server/src/commands/start.ts index 08cd82989..013cab2dc 100644 --- a/packages/server/src/commands/start.ts +++ b/packages/server/src/commands/start.ts @@ -19,6 +19,8 @@ export default class Start extends Command { FLOWISE_USERNAME: Flags.string(), FLOWISE_PASSWORD: Flags.string(), PORT: Flags.string(), + CORS_ORIGINS: Flags.string(), + IFRAME_ORIGINS: Flags.string(), DEBUG: Flags.string(), APIKEY_PATH: Flags.string(), SECRETKEY_PATH: Flags.string(), @@ -78,6 +80,8 @@ export default class Start extends Command { const { flags } = await this.parse(Start) if (flags.PORT) process.env.PORT = flags.PORT + if (flags.CORS_ORIGINS) process.env.CORS_ORIGINS = flags.CORS_ORIGINS + if (flags.IFRAME_ORIGINS) process.env.IFRAME_ORIGINS = flags.IFRAME_ORIGINS if (flags.DEBUG) process.env.DEBUG = flags.DEBUG if (flags.NUMBER_OF_PROXIES) process.env.NUMBER_OF_PROXIES = flags.NUMBER_OF_PROXIES diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 14685aee7..adc3b0c67 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -62,7 +62,7 @@ import { CachePool } from './CachePool' import { ICommonObject, IMessage, INodeOptionsValue, handleEscapeCharacters } from 'flowise-components' import { createRateLimiter, getRateLimiter, initializeRateLimiter } from './utils/rateLimit' import { addAPIKey, compareKeys, deleteAPIKey, getApiKey, getAPIKeys, updateAPIKey } from './utils/apiKey' -import { sanitizeMiddleware, getAllowedCorsOrigins, getAllowedEmbeddingOrigins } from './utils/XSS' +import { sanitizeMiddleware, getCorsOptions, getAllowedIframeOrigins } from './utils/XSS' import axios from 'axios' import { Client } from 'langchainhub' import { parsePrompt } from './utils/hub' @@ -127,21 +127,11 @@ export class App { this.app.set('trust proxy', parseInt(process.env.NUMBER_OF_PROXIES)) // Allow access from specified domains - const corsOptions = { - origin: function (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) { - const allowedOrigins = getAllowedCorsOrigins() - if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { - callback(null, true) - } else { - callback(new Error('Not allowed by CORS')) - } - } - } - this.app.use(cors(corsOptions)) + this.app.use(cors(getCorsOptions())) // Allow embedding from specified domains. this.app.use((req, res, next) => { - const allowedOrigins = getAllowedEmbeddingOrigins() + const allowedOrigins = getAllowedIframeOrigins() if (allowedOrigins == '*') { next() } else { @@ -1884,16 +1874,7 @@ export async function start(): Promise { const server = http.createServer(serverApp.app) const io = new Server(server, { - cors: { - origin: function (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) { - const allowedOrigins = getAllowedCorsOrigins() - if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { - callback(null, true) - } else { - callback(new Error('Not allowed by CORS')) - } - } - } + cors: getCorsOptions() }) await serverApp.initDatabase() diff --git a/packages/server/src/utils/XSS.ts b/packages/server/src/utils/XSS.ts index a9ad92786..d4acef49f 100644 --- a/packages/server/src/utils/XSS.ts +++ b/packages/server/src/utils/XSS.ts @@ -24,8 +24,22 @@ export function getAllowedCorsOrigins(): string { return process.env.CORS_ORIGINS ?? '*' } -export function getAllowedEmbeddingOrigins(): string { +export function getCorsOptions(): any { + const corsOptions = { + origin: function (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) { + const allowedOrigins = getAllowedCorsOrigins() + if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { + callback(null, true) + } else { + callback(new Error('Not allowed by CORS')) + } + } + } + return corsOptions +} + +export function getAllowedIframeOrigins(): string { // Expects FQDN separated by commas, otherwise nothing or * for all. // Also CSP allowed values: self or none - return process.env.EMBEDDING_ORIGINS ?? '*' + return process.env.IFRAME_ORIGINS ?? '*' } From 089928aaa89766e99115e936f3704d3bae14a90d Mon Sep 17 00:00:00 2001 From: automaton82 Date: Thu, 25 Jan 2024 15:43:42 -0500 Subject: [PATCH 10/40] Return no result with disallowed for CORS response, not an error --- packages/server/src/utils/XSS.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/utils/XSS.ts b/packages/server/src/utils/XSS.ts index d4acef49f..96bbab573 100644 --- a/packages/server/src/utils/XSS.ts +++ b/packages/server/src/utils/XSS.ts @@ -31,7 +31,7 @@ export function getCorsOptions(): any { if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { callback(null, true) } else { - callback(new Error('Not allowed by CORS')) + callback(null, false) } } } From 5b126c60bc54f1972cff1a55100fab1b71d25a31 Mon Sep 17 00:00:00 2001 From: Jared Tracy Date: Thu, 25 Jan 2024 17:16:11 -0600 Subject: [PATCH 11/40] adds DATABASE_SSL_KEY_BASE64 for pg connection DATABASE_SSL_KEY_BASE64 takes priority over DATABASE_SSL env var If neither are provided, no ssl value will be used. This allows for the usage of PGSSLMODE --- CONTRIBUTING.md | 1 + docker/.env.example | 1 + docker/docker-compose.yml | 1 + packages/server/.env.example | 1 + packages/server/src/DataSource.ts | 13 ++++++++++++- packages/server/src/commands/start.ts | 2 ++ 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 88d1aaacd..e51c79c62 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -138,6 +138,7 @@ Flowise support different environment variables to configure your instance. You | DATABASE_USER | Database username (When DATABASE_TYPE is not sqlite) | String | | | DATABASE_PASSWORD | Database password (When DATABASE_TYPE is not sqlite) | String | | | DATABASE_NAME | Database name (When DATABASE_TYPE is not sqlite) | String | | +| DATABASE_SSL_KEY_BASE64 | Database SSL client cert in base64 (takes priority over DATABASE_SSL) | Boolean | false | | DATABASE_SSL | Database connection overssl (When DATABASE_TYPE is postgre) | Boolean | false | | SECRETKEY_PATH | Location where encryption key (used to encrypt/decrypt credentials) is saved | String | `your-path/Flowise/packages/server` | | FLOWISE_SECRETKEY_OVERWRITE | Encryption key to be used instead of the key stored in SECRETKEY_PATH | String | diff --git a/docker/.env.example b/docker/.env.example index 0fe69dd1f..c703ae4b5 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -13,6 +13,7 @@ LOG_PATH=/root/.flowise/logs # DATABASE_USER="" # DATABASE_PASSWORD="" # DATABASE_SSL=true +# DATABASE_SSL_KEY_BASE64= # FLOWISE_USERNAME=user # FLOWISE_PASSWORD=1234 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index c8c88bf37..99b7c5a83 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -17,6 +17,7 @@ services: - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} - DATABASE_SSL=${DATABASE_SSL} + - DATABASE_SSL_KEY_BASE64=${DATABASE_SSL_KEY_BASE64} - APIKEY_PATH=${APIKEY_PATH} - SECRETKEY_PATH=${SECRETKEY_PATH} - FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE} diff --git a/packages/server/.env.example b/packages/server/.env.example index ed54ac66a..58812cabf 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -13,6 +13,7 @@ PORT=3000 # DATABASE_USER="" # DATABASE_PASSWORD="" # DATABASE_SSL=true +# DATABASE_SSL_KEY_BASE64= # FLOWISE_USERNAME=user # FLOWISE_PASSWORD=1234 diff --git a/packages/server/src/DataSource.ts b/packages/server/src/DataSource.ts index 762315ac9..4cd9225fd 100644 --- a/packages/server/src/DataSource.ts +++ b/packages/server/src/DataSource.ts @@ -46,7 +46,18 @@ export const init = async (): Promise => { username: process.env.DATABASE_USER, password: process.env.DATABASE_PASSWORD, database: process.env.DATABASE_NAME, - ssl: process.env.DATABASE_SSL === 'true', + ...(process.env.DATABASE_SSL_KEY_BASE64 + ? { + ssl: { + rejectUnauthorized: false, + cert: Buffer.from(process.env.DATABASE_SSL_KEY_BASE64, 'base64') + } + } + : process.env.DATABASE_SSL === 'true' + ? { + ssl: true + } + : {}), synchronize: false, migrationsRun: false, entities: Object.values(entities), diff --git a/packages/server/src/commands/start.ts b/packages/server/src/commands/start.ts index 08cd82989..09ce2aa4c 100644 --- a/packages/server/src/commands/start.ts +++ b/packages/server/src/commands/start.ts @@ -36,6 +36,7 @@ export default class Start extends Command { DATABASE_USER: Flags.string(), DATABASE_PASSWORD: Flags.string(), DATABASE_SSL: Flags.string(), + DATABASE_SSL_KEY_BASE64: Flags.string(), LANGCHAIN_TRACING_V2: Flags.string(), LANGCHAIN_ENDPOINT: Flags.string(), LANGCHAIN_API_KEY: Flags.string(), @@ -107,6 +108,7 @@ export default class Start extends Command { if (flags.DATABASE_USER) process.env.DATABASE_USER = flags.DATABASE_USER if (flags.DATABASE_PASSWORD) process.env.DATABASE_PASSWORD = flags.DATABASE_PASSWORD if (flags.DATABASE_SSL) process.env.DATABASE_SSL = flags.DATABASE_SSL + if (flags.DATABASE_SSL_KEY_BASE64) process.env.DATABASE_SSL_KEY_BASE64 = flags.DATABASE_SSL_KEY_BASE64 // Langsmith tracing if (flags.LANGCHAIN_TRACING_V2) process.env.LANGCHAIN_TRACING_V2 = flags.LANGCHAIN_TRACING_V2 From a711e21ac78f910b037e1165d8b2346fc16cffed Mon Sep 17 00:00:00 2001 From: Henry Date: Sat, 27 Jan 2024 00:52:23 +0000 Subject: [PATCH 12/40] update embeddings and marketplace templates --- .../nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts | 2 +- .../OpenAIEmbedding/OpenAIEmbedding.ts | 27 +++++- .../chatflows/API Agent OpenAI.json | 44 +++++++++- .../marketplaces/chatflows/API Agent.json | 66 ++++++++++++++- .../marketplaces/chatflows/Antonym.json | 34 +++++++- .../marketplaces/chatflows/AutoGPT.json | 49 ++++++++++- .../marketplaces/chatflows/BabyAGI.json | 37 +++++++- .../marketplaces/chatflows/CSV Agent.json | 22 ++++- .../chatflows/Chat with a Podcast.json | 49 ++++++++++- .../marketplaces/chatflows/ChatGPTPlugin.json | 22 ++++- .../chatflows/Conversational Agent.json | 22 ++++- .../Conversational Retrieval Agent.json | 37 +++++++- .../Conversational Retrieval QA Chain.json | 37 +++++++- .../chatflows/Flowise Docs QnA.json | 49 ++++++++++- .../chatflows/HuggingFace LLM Chain.json | 12 ++- .../server/marketplaces/chatflows/IfElse.json | 38 +++++++-- .../chatflows/Image Generation.json | 34 +++++++- .../chatflows/Input Moderation.json | 10 ++- .../chatflows/List Output Parser.json | 34 +++++++- .../chatflows/Long Term Memory.json | 37 +++++++- .../chatflows/Metadata Filter.json | 37 +++++++- .../chatflows/Multi Prompt Chain.json | 22 ++++- .../chatflows/Multi Retrieval QA Chain.json | 37 +++++++- .../chatflows/Multiple VectorDB.json | 84 +++++++++++++++++-- .../marketplaces/chatflows/OpenAI Agent.json | 22 ++++- .../Prompt Chaining with VectorStore.json | 71 ++++++++++++++-- .../chatflows/Prompt Chaining.json | 24 +++++- .../marketplaces/chatflows/ReAct Agent.json | 10 ++- .../marketplaces/chatflows/Replicate LLM.json | 12 ++- .../marketplaces/chatflows/SQL DB Chain.json | 22 ++++- .../marketplaces/chatflows/SQL Prompt.json | 30 ++++++- .../chatflows/Simple Conversation Chain.json | 10 ++- .../chatflows/Simple LLM Chain.json | 12 ++- .../chatflows/Structured Output Parser.json | 34 +++++++- .../marketplaces/chatflows/Translator.json | 34 +++++++- .../marketplaces/chatflows/WebBrowser.json | 71 +++++++++++++++- .../marketplaces/chatflows/WebPage QnA.json | 37 +++++++- 37 files changed, 1143 insertions(+), 88 deletions(-) diff --git a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts index 5f321900d..2cb701c18 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts @@ -19,7 +19,7 @@ class ChatOpenAI_ChatModels implements INode { constructor() { this.label = 'ChatOpenAI' this.name = 'chatOpenAI' - this.version = 2.0 + this.version = 3.0 this.type = 'ChatOpenAI' this.icon = 'openai.svg' this.category = 'Chat Models' diff --git a/packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts b/packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts index b3d0045b4..7deec67e9 100644 --- a/packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts +++ b/packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts @@ -17,7 +17,7 @@ class OpenAIEmbedding_Embeddings implements INode { constructor() { this.label = 'OpenAI Embeddings' this.name = 'openAIEmbeddings' - this.version = 1.0 + this.version = 2.0 this.type = 'OpenAIEmbeddings' this.icon = 'openai.svg' this.category = 'Embeddings' @@ -30,6 +30,27 @@ class OpenAIEmbedding_Embeddings implements INode { credentialNames: ['openAIApi'] } this.inputs = [ + { + label: 'Model Name', + name: 'modelName', + type: 'options', + options: [ + { + label: 'text-embedding-3-large', + name: 'text-embedding-3-large' + }, + { + label: 'text-embedding-3-small', + name: 'text-embedding-3-small' + }, + { + label: 'text-embedding-ada-002', + name: 'text-embedding-ada-002' + } + ], + default: 'text-embedding-ada-002', + optional: true + }, { label: 'Strip New Lines', name: 'stripNewLines', @@ -66,12 +87,14 @@ class OpenAIEmbedding_Embeddings implements INode { const batchSize = nodeData.inputs?.batchSize as string const timeout = nodeData.inputs?.timeout as string const basePath = nodeData.inputs?.basepath as string + const modelName = nodeData.inputs?.modelName as string const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) const obj: Partial & { openAIApiKey?: string } = { - openAIApiKey + openAIApiKey, + modelName } if (stripNewLines) obj.stripNewLines = stripNewLines diff --git a/packages/server/marketplaces/chatflows/API Agent OpenAI.json b/packages/server/marketplaces/chatflows/API Agent OpenAI.json index 002c08c18..87f6d6d2e 100644 --- a/packages/server/marketplaces/chatflows/API Agent OpenAI.json +++ b/packages/server/marketplaces/chatflows/API Agent OpenAI.json @@ -88,7 +88,7 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -111,6 +111,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -127,6 +143,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -407,7 +427,7 @@ "data": { "id": "chatOpenAI_2", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -430,6 +450,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -446,6 +482,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/API Agent.json b/packages/server/marketplaces/chatflows/API Agent.json index eabc8f2ed..af99be9d0 100644 --- a/packages/server/marketplaces/chatflows/API Agent.json +++ b/packages/server/marketplaces/chatflows/API Agent.json @@ -396,7 +396,7 @@ "data": { "id": "chatOpenAI_2", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -419,6 +419,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -435,6 +451,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -567,7 +587,7 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -590,6 +610,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -606,6 +642,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -738,7 +778,7 @@ "data": { "id": "chatOpenAI_3", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -761,6 +801,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -777,6 +833,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/Antonym.json b/packages/server/marketplaces/chatflows/Antonym.json index 85cd5e4c9..ef997feb5 100644 --- a/packages/server/marketplaces/chatflows/Antonym.json +++ b/packages/server/marketplaces/chatflows/Antonym.json @@ -175,7 +175,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -198,6 +198,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -214,6 +230,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -381,13 +401,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", "prompt": "{{fewShotPromptTemplate_1.data.instance}}", "outputParser": "", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/AutoGPT.json b/packages/server/marketplaces/chatflows/AutoGPT.json index 0062cd43f..30ea96ae3 100644 --- a/packages/server/marketplaces/chatflows/AutoGPT.json +++ b/packages/server/marketplaces/chatflows/AutoGPT.json @@ -251,7 +251,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -274,6 +274,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -290,6 +306,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -422,7 +442,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -436,6 +456,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -474,7 +516,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/BabyAGI.json b/packages/server/marketplaces/chatflows/BabyAGI.json index 81e3f2307..d0c74fcbc 100644 --- a/packages/server/marketplaces/chatflows/BabyAGI.json +++ b/packages/server/marketplaces/chatflows/BabyAGI.json @@ -77,7 +77,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -91,6 +91,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -129,7 +151,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -321,7 +344,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -344,6 +367,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/CSV Agent.json b/packages/server/marketplaces/chatflows/CSV Agent.json index 61d97c4dd..e16377d27 100644 --- a/packages/server/marketplaces/chatflows/CSV Agent.json +++ b/packages/server/marketplaces/chatflows/CSV Agent.json @@ -70,7 +70,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 2, + "version": 3, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -92,6 +92,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -108,6 +124,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/Chat with a Podcast.json b/packages/server/marketplaces/chatflows/Chat with a Podcast.json index 0a5d4ac6e..f8d8d26c7 100644 --- a/packages/server/marketplaces/chatflows/Chat with a Podcast.json +++ b/packages/server/marketplaces/chatflows/Chat with a Podcast.json @@ -194,7 +194,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -217,6 +217,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -233,6 +249,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -440,7 +460,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -454,6 +474,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -492,7 +534,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/ChatGPTPlugin.json b/packages/server/marketplaces/chatflows/ChatGPTPlugin.json index b8e2cf01c..12bea993e 100644 --- a/packages/server/marketplaces/chatflows/ChatGPTPlugin.json +++ b/packages/server/marketplaces/chatflows/ChatGPTPlugin.json @@ -215,7 +215,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 2, + "version": 3, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -237,6 +237,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -253,6 +269,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/Conversational Agent.json b/packages/server/marketplaces/chatflows/Conversational Agent.json index b27d38863..031a29c01 100644 --- a/packages/server/marketplaces/chatflows/Conversational Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Agent.json @@ -156,7 +156,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -179,6 +179,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -195,6 +211,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json index 4378a47d6..3b9a8c215 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json @@ -14,7 +14,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -28,6 +28,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -66,7 +88,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -456,7 +479,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -479,6 +502,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json index 253a1dfc7..1dfe1e336 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json @@ -14,7 +14,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -28,6 +28,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -66,7 +88,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -346,7 +369,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -369,6 +392,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Flowise Docs QnA.json b/packages/server/marketplaces/chatflows/Flowise Docs QnA.json index 16f708015..6975fc686 100644 --- a/packages/server/marketplaces/chatflows/Flowise Docs QnA.json +++ b/packages/server/marketplaces/chatflows/Flowise Docs QnA.json @@ -376,7 +376,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 2, + "version": 3, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -398,6 +398,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -414,6 +430,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -547,7 +567,7 @@ "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", "name": "openAIEmbeddings", - "version": 1, + "version": 2, "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], "category": "Embeddings", @@ -560,6 +580,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -598,7 +640,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json b/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json index 5e33b63ac..930095741 100644 --- a/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json +++ b/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json @@ -234,13 +234,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{huggingFaceInference_LLMs_0.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/IfElse.json b/packages/server/marketplaces/chatflows/IfElse.json index 690d3ce55..f3fddebf4 100644 --- a/packages/server/marketplaces/chatflows/IfElse.json +++ b/packages/server/marketplaces/chatflows/IfElse.json @@ -489,13 +489,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{openAI_1.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "FirstChain" + "chainName": "FirstChain", + "inputModeration": "" }, "outputAnchors": [ { @@ -578,13 +588,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_1-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_1-input-inputModeration-Moderation" } ], "inputs": { "model": "{{openAI_2.data.instance}}", "prompt": "{{promptTemplate_1.data.instance}}", "outputParser": "", - "chainName": "LastChain" + "chainName": "LastChain", + "inputModeration": "" }, "outputAnchors": [ { @@ -742,8 +762,8 @@ "model": "{{chatOpenAI_0.data.instance}}", "prompt": "{{promptTemplate_2.data.instance}}", "outputParser": "", - "inputModeration": "", - "chainName": "FallbackChain" + "chainName": "FallbackChain", + "inputModeration": "" }, "outputAnchors": [ { @@ -888,7 +908,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -911,6 +931,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Image Generation.json b/packages/server/marketplaces/chatflows/Image Generation.json index 98d12238f..7dafcedf9 100644 --- a/packages/server/marketplaces/chatflows/Image Generation.json +++ b/packages/server/marketplaces/chatflows/Image Generation.json @@ -289,13 +289,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{replicate_0.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { @@ -378,13 +388,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_1-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_1-input-inputModeration-Moderation" } ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", "prompt": "{{promptTemplate_1.data.instance}}", "outputParser": "", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { @@ -432,7 +452,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -455,6 +475,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Input Moderation.json b/packages/server/marketplaces/chatflows/Input Moderation.json index 1f6cc6245..ed823a21c 100644 --- a/packages/server/marketplaces/chatflows/Input Moderation.json +++ b/packages/server/marketplaces/chatflows/Input Moderation.json @@ -164,7 +164,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -187,6 +187,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/List Output Parser.json b/packages/server/marketplaces/chatflows/List Output Parser.json index 33841d153..eaf56dff4 100644 --- a/packages/server/marketplaces/chatflows/List Output Parser.json +++ b/packages/server/marketplaces/chatflows/List Output Parser.json @@ -49,13 +49,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "{{csvOutputParser_0.data.instance}}", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { @@ -213,7 +223,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -236,6 +246,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -252,6 +278,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/Long Term Memory.json b/packages/server/marketplaces/chatflows/Long Term Memory.json index cf0fa4d44..1b3e48e17 100644 --- a/packages/server/marketplaces/chatflows/Long Term Memory.json +++ b/packages/server/marketplaces/chatflows/Long Term Memory.json @@ -112,7 +112,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -126,6 +126,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -164,7 +186,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -483,7 +506,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -506,6 +529,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Metadata Filter.json b/packages/server/marketplaces/chatflows/Metadata Filter.json index f7b2fbfb1..f96e07c28 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter.json @@ -346,7 +346,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -360,6 +360,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -398,7 +420,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -430,7 +453,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -453,6 +476,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Multi Prompt Chain.json b/packages/server/marketplaces/chatflows/Multi Prompt Chain.json index 0a888a6b7..314e24a6a 100644 --- a/packages/server/marketplaces/chatflows/Multi Prompt Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Prompt Chain.json @@ -278,7 +278,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 2, + "version": 3, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -300,6 +300,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -316,6 +332,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json index e86b28c93..f685e43b1 100644 --- a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json @@ -281,7 +281,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -295,6 +295,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -333,7 +355,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -365,7 +388,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -388,6 +411,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Multiple VectorDB.json b/packages/server/marketplaces/chatflows/Multiple VectorDB.json index d53cb55ee..e5a16caa8 100644 --- a/packages/server/marketplaces/chatflows/Multiple VectorDB.json +++ b/packages/server/marketplaces/chatflows/Multiple VectorDB.json @@ -271,7 +271,7 @@ "data": { "id": "openAIEmbeddings_1", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -285,6 +285,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_1-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_1-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -323,7 +345,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -355,7 +378,7 @@ "data": { "id": "openAIEmbeddings_2", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -369,6 +392,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_2-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_2-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -407,7 +452,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -439,7 +485,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -462,6 +508,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" @@ -949,7 +1003,7 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -972,6 +1026,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" @@ -1139,7 +1201,7 @@ "data": { "id": "chatOpenAI_2", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -1162,6 +1224,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/OpenAI Agent.json b/packages/server/marketplaces/chatflows/OpenAI Agent.json index 17e59236d..e3e80dcc0 100644 --- a/packages/server/marketplaces/chatflows/OpenAI Agent.json +++ b/packages/server/marketplaces/chatflows/OpenAI Agent.json @@ -279,7 +279,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -302,6 +302,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -318,6 +334,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json index 0ddec74fd..46e1257d2 100644 --- a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json +++ b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json @@ -264,13 +264,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_2-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_2-input-inputModeration-Moderation" } ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "RephraseQuestion" + "chainName": "RephraseQuestion", + "inputModeration": "" }, "outputAnchors": [ { @@ -353,13 +363,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_1-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_1-input-inputModeration-Moderation" } ], "inputs": { "model": "{{chatOpenAI_1.data.instance}}", "prompt": "{{chatPromptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "FinalResponse" + "chainName": "FinalResponse", + "inputModeration": "" }, "outputAnchors": [ { @@ -407,7 +427,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -430,6 +450,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" @@ -597,7 +625,7 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -620,6 +648,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" @@ -934,7 +970,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -948,6 +984,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -986,7 +1044,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining.json b/packages/server/marketplaces/chatflows/Prompt Chaining.json index 3181bc472..267d8222d 100644 --- a/packages/server/marketplaces/chatflows/Prompt Chaining.json +++ b/packages/server/marketplaces/chatflows/Prompt Chaining.json @@ -488,13 +488,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{openAI_1.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "FirstChain" + "chainName": "FirstChain", + "inputModeration": "" }, "outputAnchors": [ { @@ -577,13 +587,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_1-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_1-input-inputModeration-Moderation" } ], "inputs": { "model": "{{openAI_2.data.instance}}", "prompt": "{{promptTemplate_1.data.instance}}", "outputParser": "", - "chainName": "LastChain" + "chainName": "LastChain", + "inputModeration": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/ReAct Agent.json b/packages/server/marketplaces/chatflows/ReAct Agent.json index b776dd37b..e4a7fab80 100644 --- a/packages/server/marketplaces/chatflows/ReAct Agent.json +++ b/packages/server/marketplaces/chatflows/ReAct Agent.json @@ -99,7 +99,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -122,6 +122,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Replicate LLM.json b/packages/server/marketplaces/chatflows/Replicate LLM.json index bee565ce6..832e85c7b 100644 --- a/packages/server/marketplaces/chatflows/Replicate LLM.json +++ b/packages/server/marketplaces/chatflows/Replicate LLM.json @@ -227,13 +227,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{replicate_0.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/SQL DB Chain.json b/packages/server/marketplaces/chatflows/SQL DB Chain.json index 026a03d8a..92e421788 100644 --- a/packages/server/marketplaces/chatflows/SQL DB Chain.json +++ b/packages/server/marketplaces/chatflows/SQL DB Chain.json @@ -13,7 +13,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -36,6 +36,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -52,6 +68,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/SQL Prompt.json b/packages/server/marketplaces/chatflows/SQL Prompt.json index ad08fed85..406c2e524 100644 --- a/packages/server/marketplaces/chatflows/SQL Prompt.json +++ b/packages/server/marketplaces/chatflows/SQL Prompt.json @@ -173,7 +173,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -196,6 +196,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" @@ -363,7 +371,7 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -386,6 +394,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" @@ -1279,7 +1295,7 @@ "data": { "id": "chatOpenAI_2", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -1302,6 +1318,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json index 9689bf8c5..b17e8a659 100644 --- a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json +++ b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json @@ -14,7 +14,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -37,6 +37,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" diff --git a/packages/server/marketplaces/chatflows/Simple LLM Chain.json b/packages/server/marketplaces/chatflows/Simple LLM Chain.json index b07124c05..f2e3a4a22 100644 --- a/packages/server/marketplaces/chatflows/Simple LLM Chain.json +++ b/packages/server/marketplaces/chatflows/Simple LLM Chain.json @@ -268,13 +268,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{openAI_0.data.instance}}", "prompt": "{{promptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/Structured Output Parser.json b/packages/server/marketplaces/chatflows/Structured Output Parser.json index 77a8bbfd3..923364432 100644 --- a/packages/server/marketplaces/chatflows/Structured Output Parser.json +++ b/packages/server/marketplaces/chatflows/Structured Output Parser.json @@ -14,7 +14,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -37,6 +37,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -53,6 +69,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -227,13 +247,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", "prompt": "{{chatPromptTemplate_0.data.instance}}", "outputParser": "{{structuredOutputParser_0.data.instance}}", - "chainName": "" + "chainName": "", + "inputModeration": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/Translator.json b/packages/server/marketplaces/chatflows/Translator.json index f1fa0764f..0bf492525 100644 --- a/packages/server/marketplaces/chatflows/Translator.json +++ b/packages/server/marketplaces/chatflows/Translator.json @@ -82,7 +82,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -105,6 +105,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -121,6 +137,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -288,13 +308,23 @@ "type": "BaseLLMOutputParser", "optional": true, "id": "llmChain_0-input-outputParser-BaseLLMOutputParser" + }, + { + "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": "llmChain_0-input-inputModeration-Moderation" } ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", "prompt": "{{chatPromptTemplate_0.data.instance}}", "outputParser": "", - "chainName": "Language Translation" + "chainName": "Language Translation", + "inputModeration": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/WebBrowser.json b/packages/server/marketplaces/chatflows/WebBrowser.json index d905b54b0..2376e29e7 100644 --- a/packages/server/marketplaces/chatflows/WebBrowser.json +++ b/packages/server/marketplaces/chatflows/WebBrowser.json @@ -125,7 +125,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -148,6 +148,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -164,6 +180,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" @@ -296,7 +316,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -310,6 +330,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -348,7 +390,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -380,7 +423,7 @@ "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -403,6 +446,22 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, { "label": "gpt-4-0613", "name": "gpt-4-0613" @@ -419,6 +478,10 @@ "label": "gpt-3.5-turbo", "name": "gpt-3.5-turbo" }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, { "label": "gpt-3.5-turbo-0613", "name": "gpt-3.5-turbo-0613" diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index df05feef4..4013985ea 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -14,7 +14,7 @@ "data": { "id": "openAIEmbeddings_0", "label": "OpenAI Embeddings", - "version": 1, + "version": 2, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", "baseClasses": ["OpenAIEmbeddings", "Embeddings"], @@ -28,6 +28,28 @@ "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "text-embedding-3-large", + "name": "text-embedding-3-large" + }, + { + "label": "text-embedding-3-small", + "name": "text-embedding-3-small" + }, + { + "label": "text-embedding-ada-002", + "name": "text-embedding-ada-002" + } + ], + "default": "text-embedding-ada-002", + "optional": true, + "id": "openAIEmbeddings_0-input-modelName-options" + }, { "label": "Strip New Lines", "name": "stripNewLines", @@ -66,7 +88,8 @@ "stripNewLines": "", "batchSize": "", "timeout": "", - "basepath": "" + "basepath": "", + "modelName": "text-embedding-ada-002" }, "outputAnchors": [ { @@ -369,7 +392,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 2, + "version": 3, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -392,6 +415,14 @@ "label": "gpt-4", "name": "gpt-4" }, + { + "label": "gpt-4-turbo-preview", + "name": "gpt-4-turbo-preview" + }, + { + "label": "gpt-4-0125-preview", + "name": "gpt-4-0125-preview" + }, { "label": "gpt-4-1106-preview", "name": "gpt-4-1106-preview" From 29d840c09e0486491a8dfbdc35ffb65f70ae3720 Mon Sep 17 00:00:00 2001 From: Henry Date: Sat, 27 Jan 2024 00:56:33 +0000 Subject: [PATCH 13/40] update pinecone marketplace version --- packages/server/marketplaces/chatflows/AutoGPT.json | 2 +- packages/server/marketplaces/chatflows/BabyAGI.json | 2 +- .../marketplaces/chatflows/Conversational Retrieval Agent.json | 2 +- .../chatflows/Conversational Retrieval QA Chain.json | 2 +- packages/server/marketplaces/chatflows/Metadata Filter.json | 2 +- .../server/marketplaces/chatflows/Multi Retrieval QA Chain.json | 2 +- packages/server/marketplaces/chatflows/WebPage QnA.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/server/marketplaces/chatflows/AutoGPT.json b/packages/server/marketplaces/chatflows/AutoGPT.json index 30ea96ae3..4edbf8231 100644 --- a/packages/server/marketplaces/chatflows/AutoGPT.json +++ b/packages/server/marketplaces/chatflows/AutoGPT.json @@ -549,7 +549,7 @@ "data": { "id": "pinecone_0", "label": "Pinecone", - "version": 1, + "version": 2, "name": "pinecone", "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], diff --git a/packages/server/marketplaces/chatflows/BabyAGI.json b/packages/server/marketplaces/chatflows/BabyAGI.json index d0c74fcbc..3137d5117 100644 --- a/packages/server/marketplaces/chatflows/BabyAGI.json +++ b/packages/server/marketplaces/chatflows/BabyAGI.json @@ -184,7 +184,7 @@ "data": { "id": "pinecone_0", "label": "Pinecone", - "version": 1, + "version": 2, "name": "pinecone", "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json index 3b9a8c215..810c2b354 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json @@ -319,7 +319,7 @@ "data": { "id": "pinecone_0", "label": "Pinecone", - "version": 1, + "version": 2, "name": "pinecone", "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json index 1dfe1e336..e73a9d28a 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json @@ -567,7 +567,7 @@ "data": { "id": "pinecone_0", "label": "Pinecone", - "version": 1, + "version": 2, "name": "pinecone", "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], diff --git a/packages/server/marketplaces/chatflows/Metadata Filter.json b/packages/server/marketplaces/chatflows/Metadata Filter.json index f96e07c28..ef9288542 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter.json @@ -651,7 +651,7 @@ "data": { "id": "pinecone_0", "label": "Pinecone", - "version": 1, + "version": 2, "name": "pinecone", "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], diff --git a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json index f685e43b1..8c9e8537c 100644 --- a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json @@ -586,7 +586,7 @@ "data": { "id": "pinecone_0", "label": "Pinecone", - "version": 1, + "version": 2, "name": "pinecone", "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index 4013985ea..a5a532331 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -669,7 +669,7 @@ "data": { "id": "pinecone_0", "label": "Pinecone", - "version": 1, + "version": 3, "name": "pinecone", "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], From e8deeb25cff10b8d17393de3632b6febcee8c336 Mon Sep 17 00:00:00 2001 From: Anuj Verma <42962743+Ashes47@users.noreply.github.com> Date: Sun, 28 Jan 2024 19:45:19 +0530 Subject: [PATCH 14/40] Update MongoDBMemory.ts --- .../memory/MongoDBMemory/MongoDBMemory.ts | 145 +++++++++--------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts index c593c20d6..b35de5ae8 100644 --- a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts +++ b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts @@ -1,9 +1,19 @@ -import { MongoClient, Collection, Document } from 'mongodb' -import { MongoDBChatMessageHistory } from 'langchain/stores/message/mongodb' -import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } from 'langchain/schema' -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' -import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' +import { MongoClient, Collection, Document } from 'mongodb'; +import { MongoDBChatMessageHistory } from 'langchain/stores/message/mongodb'; +import { BufferMemory, BufferMemoryInput } from 'langchain/memory'; +import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } from 'langchain/schema'; +import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'; +import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface'; + +let mongoClientSingleton = null; + +const getMongoClient = async (mongoDBConnectUrl) => { + if (!mongoClientSingleton) { + mongoClientSingleton = new MongoClient(mongoDBConnectUrl, { useNewUrlParser: true, useUnifiedTopology: true }); + await mongoClientSingleton.connect(); + } + return mongoClientSingleton; +}; class MongoDB_Memory implements INode { label: string @@ -18,20 +28,20 @@ class MongoDB_Memory implements INode { inputs: INodeParams[] constructor() { - this.label = 'MongoDB Atlas Chat Memory' - this.name = 'MongoDBAtlasChatMemory' - this.version = 1.0 - this.type = 'MongoDBAtlasChatMemory' - this.icon = 'mongodb.svg' - this.category = 'Memory' - this.description = 'Stores the conversation in MongoDB Atlas' - this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] + this.label = 'MongoDB Atlas Chat Memory'; + this.name = 'MongoDBAtlasChatMemory'; + this.version = 1.0; + this.type = 'MongoDBAtlasChatMemory'; + this.icon = 'mongodb.svg'; + this.category = 'Memory'; + this.description = 'Stores the conversation in MongoDB Atlas'; + this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)]; this.credential = { label: 'Connect Credential', name: 'credential', type: 'credential', credentialNames: ['mongoDBUrlApi'] - } + }; this.inputs = [ { label: 'Database', @@ -49,8 +59,7 @@ class MongoDB_Memory implements INode { label: 'Session Id', name: 'sessionId', type: 'string', - description: - 'If not specified, a random id will be used. Learn more', + description: 'If not specified, a random id will be used. Learn more', default: '', additionalParams: true, optional: true @@ -62,128 +71,126 @@ class MongoDB_Memory implements INode { default: 'chat_history', additionalParams: true } - ] + ]; } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - return initializeMongoDB(nodeData, options) + return initializeMongoDB(nodeData, options); } } const initializeMongoDB = async (nodeData: INodeData, options: ICommonObject): Promise => { - const databaseName = nodeData.inputs?.databaseName as string - const collectionName = nodeData.inputs?.collectionName as string - const memoryKey = nodeData.inputs?.memoryKey as string - const sessionId = nodeData.inputs?.sessionId as string + const databaseName = nodeData.inputs?.databaseName as string; + const collectionName = nodeData.inputs?.collectionName as string; + const memoryKey = nodeData.inputs?.memoryKey as string; + const sessionId = nodeData.inputs?.sessionId as string; - const credentialData = await getCredentialData(nodeData.credential ?? '', options) - const mongoDBConnectUrl = getCredentialParam('mongoDBConnectUrl', credentialData, nodeData) + const credentialData = await getCredentialData(nodeData.credential ?? '', options); + const mongoDBConnectUrl = getCredentialParam('mongoDBConnectUrl', credentialData, nodeData); - const client = new MongoClient(mongoDBConnectUrl) - await client.connect() - - const collection = client.db(databaseName).collection(collectionName) + const client = await getMongoClient(mongoDBConnectUrl); + const collection = client.db(databaseName).collection(collectionName); const mongoDBChatMessageHistory = new MongoDBChatMessageHistory({ collection, sessionId - }) + }); mongoDBChatMessageHistory.getMessages = async (): Promise => { const document = await collection.findOne({ sessionId: (mongoDBChatMessageHistory as any).sessionId - }) - const messages = document?.messages || [] - return messages.map(mapStoredMessageToChatMessage) - } + }); + const messages = document?.messages || []; + return messages.map(mapStoredMessageToChatMessage); + }; mongoDBChatMessageHistory.addMessage = async (message: BaseMessage): Promise => { - const messages = [message].map((msg) => msg.toDict()) + const messages = [message].map((msg) => msg.toDict()); await collection.updateOne( { sessionId: (mongoDBChatMessageHistory as any).sessionId }, { $push: { messages: { $each: messages } } }, { upsert: true } - ) - } + ); + }; mongoDBChatMessageHistory.clear = async (): Promise => { - await collection.deleteOne({ sessionId: (mongoDBChatMessageHistory as any).sessionId }) - } + await collection.deleteOne({ sessionId: (mongoDBChatMessageHistory as any).sessionId }); + }; return new BufferMemoryExtended({ memoryKey: memoryKey ?? 'chat_history', chatHistory: mongoDBChatMessageHistory, sessionId, collection - }) -} + }); +}; interface BufferMemoryExtendedInput { - collection: Collection - sessionId: string + collection: Collection; + sessionId: string; } class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { - sessionId = '' - collection: Collection + sessionId = ''; + collection: Collection; constructor(fields: BufferMemoryInput & BufferMemoryExtendedInput) { - super(fields) - this.sessionId = fields.sessionId - this.collection = fields.collection + super(fields); + this.sessionId = fields.sessionId; + this.collection = fields.collection; } async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { - if (!this.collection) return [] + if (!this.collection) return []; - const id = overrideSessionId ?? this.sessionId - const document = await this.collection.findOne({ sessionId: id }) - const messages = document?.messages || [] - const baseMessages = messages.map(mapStoredMessageToChatMessage) - return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) + const id = overrideSessionId ?? this.sessionId; + const document = await this.collection.findOne({ sessionId: id }); + const messages = document?.messages || []; + const baseMessages = messages.map(mapStoredMessageToChatMessage); + return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages); } async addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId = ''): Promise { - if (!this.collection) return + if (!this.collection) return; - const id = overrideSessionId ?? this.sessionId - const input = msgArray.find((msg) => msg.type === 'userMessage') - const output = msgArray.find((msg) => msg.type === 'apiMessage') + const id = overrideSessionId ?? this.sessionId; + const input = msgArray.find((msg) => msg.type === 'userMessage'); + const output = msgArray.find((msg) => msg.type === 'apiMessage'); if (input) { - const newInputMessage = new HumanMessage(input.text) - const messageToAdd = [newInputMessage].map((msg) => msg.toDict()) + const newInputMessage = new HumanMessage(input.text); + const messageToAdd = [newInputMessage].map((msg) => msg.toDict()); await this.collection.updateOne( { sessionId: id }, { $push: { messages: { $each: messageToAdd } } }, { upsert: true } - ) + ); } if (output) { - const newOutputMessage = new AIMessage(output.text) - const messageToAdd = [newOutputMessage].map((msg) => msg.toDict()) + const newOutputMessage = new AIMessage(output.text); + const messageToAdd = [newOutputMessage].map((msg) => msg.toDict()); await this.collection.updateOne( { sessionId: id }, { $push: { messages: { $each: messageToAdd } } }, { upsert: true } - ) + ); } } async clearChatMessages(overrideSessionId = ''): Promise { - if (!this.collection) return + if (!this.collection) return; - const id = overrideSessionId ?? this.sessionId - await this.collection.deleteOne({ sessionId: id }) - await this.clear() + const id = overrideSessionId ?? this.sessionId; + await this.collection.deleteOne({ sessionId: id }); + await this.clear(); } } -module.exports = { nodeClass: MongoDB_Memory } +module.exports = { nodeClass: MongoDB_Memory }; From e154461f1dac59415f867ed5acee7e0f6d195cdb Mon Sep 17 00:00:00 2001 From: Anuj Verma <42962743+Ashes47@users.noreply.github.com> Date: Sun, 28 Jan 2024 21:33:09 +0530 Subject: [PATCH 15/40] Update MongoDBMemory.ts --- .../memory/MongoDBMemory/MongoDBMemory.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts index b35de5ae8..c2c7ada60 100644 --- a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts +++ b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts @@ -1,19 +1,19 @@ -import { MongoClient, Collection, Document } from 'mongodb'; -import { MongoDBChatMessageHistory } from 'langchain/stores/message/mongodb'; -import { BufferMemory, BufferMemoryInput } from 'langchain/memory'; -import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } from 'langchain/schema'; -import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'; -import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface'; +import { MongoClient, Collection, Document } from 'mongodb' +import { MongoDBChatMessageHistory } from 'langchain/stores/message/mongodb' +import { BufferMemory, BufferMemoryInput } from 'langchain/memory' +import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } from 'langchain/schema' +import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' -let mongoClientSingleton = null; +let mongoClientSingleton = null const getMongoClient = async (mongoDBConnectUrl) => { if (!mongoClientSingleton) { - mongoClientSingleton = new MongoClient(mongoDBConnectUrl, { useNewUrlParser: true, useUnifiedTopology: true }); - await mongoClientSingleton.connect(); + mongoClientSingleton = new MongoClient(mongoDBConnectUrl, { useNewUrlParser: true, useUnifiedTopology: true }) + await mongoClientSingleton.connect() } - return mongoClientSingleton; -}; + return mongoClientSingleton +} class MongoDB_Memory implements INode { label: string From 36ab1681ac455a5cea1482e98d9765eaf3042071 Mon Sep 17 00:00:00 2001 From: Ashes47 Date: Sun, 28 Jan 2024 21:39:22 +0530 Subject: [PATCH 16/40] lint --- .../memory/MongoDBMemory/MongoDBMemory.ts | 121 +++++++++--------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts index c2c7ada60..3c2903f36 100644 --- a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts +++ b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts @@ -28,20 +28,20 @@ class MongoDB_Memory implements INode { inputs: INodeParams[] constructor() { - this.label = 'MongoDB Atlas Chat Memory'; - this.name = 'MongoDBAtlasChatMemory'; - this.version = 1.0; - this.type = 'MongoDBAtlasChatMemory'; - this.icon = 'mongodb.svg'; - this.category = 'Memory'; - this.description = 'Stores the conversation in MongoDB Atlas'; - this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)]; + this.label = 'MongoDB Atlas Chat Memory' + this.name = 'MongoDBAtlasChatMemory' + this.version = 1.0 + this.type = 'MongoDBAtlasChatMemory' + this.icon = 'mongodb.svg' + this.category = 'Memory' + this.description = 'Stores the conversation in MongoDB Atlas' + this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] this.credential = { label: 'Connect Credential', name: 'credential', type: 'credential', credentialNames: ['mongoDBUrlApi'] - }; + } this.inputs = [ { label: 'Database', @@ -59,7 +59,8 @@ class MongoDB_Memory implements INode { label: 'Session Id', name: 'sessionId', type: 'string', - description: 'If not specified, a random id will be used. Learn more', + description: + 'If not specified, a random id will be used. Learn more', default: '', additionalParams: true, optional: true @@ -71,126 +72,126 @@ class MongoDB_Memory implements INode { default: 'chat_history', additionalParams: true } - ]; + ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - return initializeMongoDB(nodeData, options); + return initializeMongoDB(nodeData, options) } } const initializeMongoDB = async (nodeData: INodeData, options: ICommonObject): Promise => { - const databaseName = nodeData.inputs?.databaseName as string; - const collectionName = nodeData.inputs?.collectionName as string; - const memoryKey = nodeData.inputs?.memoryKey as string; - const sessionId = nodeData.inputs?.sessionId as string; + const databaseName = nodeData.inputs?.databaseName as string + const collectionName = nodeData.inputs?.collectionName as string + const memoryKey = nodeData.inputs?.memoryKey as string + const sessionId = nodeData.inputs?.sessionId as string - const credentialData = await getCredentialData(nodeData.credential ?? '', options); - const mongoDBConnectUrl = getCredentialParam('mongoDBConnectUrl', credentialData, nodeData); + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const mongoDBConnectUrl = getCredentialParam('mongoDBConnectUrl', credentialData, nodeData) - const client = await getMongoClient(mongoDBConnectUrl); - const collection = client.db(databaseName).collection(collectionName); + const client = await getMongoClient(mongoDBConnectUrl) + const collection = client.db(databaseName).collection(collectionName) const mongoDBChatMessageHistory = new MongoDBChatMessageHistory({ collection, sessionId - }); + }) mongoDBChatMessageHistory.getMessages = async (): Promise => { const document = await collection.findOne({ sessionId: (mongoDBChatMessageHistory as any).sessionId - }); - const messages = document?.messages || []; - return messages.map(mapStoredMessageToChatMessage); - }; + }) + const messages = document?.messages || [] + return messages.map(mapStoredMessageToChatMessage) + } mongoDBChatMessageHistory.addMessage = async (message: BaseMessage): Promise => { - const messages = [message].map((msg) => msg.toDict()); + const messages = [message].map((msg) => msg.toDict()) await collection.updateOne( { sessionId: (mongoDBChatMessageHistory as any).sessionId }, { $push: { messages: { $each: messages } } }, { upsert: true } - ); - }; + ) + } mongoDBChatMessageHistory.clear = async (): Promise => { - await collection.deleteOne({ sessionId: (mongoDBChatMessageHistory as any).sessionId }); - }; + await collection.deleteOne({ sessionId: (mongoDBChatMessageHistory as any).sessionId }) + } return new BufferMemoryExtended({ memoryKey: memoryKey ?? 'chat_history', chatHistory: mongoDBChatMessageHistory, sessionId, collection - }); -}; + }) +} interface BufferMemoryExtendedInput { - collection: Collection; - sessionId: string; + collection: Collection + sessionId: string } class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods { - sessionId = ''; - collection: Collection; + sessionId = '' + collection: Collection constructor(fields: BufferMemoryInput & BufferMemoryExtendedInput) { - super(fields); - this.sessionId = fields.sessionId; - this.collection = fields.collection; + super(fields) + this.sessionId = fields.sessionId + this.collection = fields.collection } async getChatMessages(overrideSessionId = '', returnBaseMessages = false): Promise { - if (!this.collection) return []; + if (!this.collection) return [] - const id = overrideSessionId ?? this.sessionId; - const document = await this.collection.findOne({ sessionId: id }); - const messages = document?.messages || []; - const baseMessages = messages.map(mapStoredMessageToChatMessage); - return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages); + const id = overrideSessionId ?? this.sessionId + const document = await this.collection.findOne({ sessionId: id }) + const messages = document?.messages || [] + const baseMessages = messages.map(mapStoredMessageToChatMessage) + return returnBaseMessages ? baseMessages : convertBaseMessagetoIMessage(baseMessages) } async addChatMessages(msgArray: { text: string; type: MessageType }[], overrideSessionId = ''): Promise { - if (!this.collection) return; + if (!this.collection) return - const id = overrideSessionId ?? this.sessionId; - const input = msgArray.find((msg) => msg.type === 'userMessage'); - const output = msgArray.find((msg) => msg.type === 'apiMessage'); + const id = overrideSessionId ?? this.sessionId + const input = msgArray.find((msg) => msg.type === 'userMessage') + const output = msgArray.find((msg) => msg.type === 'apiMessage') if (input) { - const newInputMessage = new HumanMessage(input.text); - const messageToAdd = [newInputMessage].map((msg) => msg.toDict()); + const newInputMessage = new HumanMessage(input.text) + const messageToAdd = [newInputMessage].map((msg) => msg.toDict()) await this.collection.updateOne( { sessionId: id }, { $push: { messages: { $each: messageToAdd } } }, { upsert: true } - ); + ) } if (output) { - const newOutputMessage = new AIMessage(output.text); - const messageToAdd = [newOutputMessage].map((msg) => msg.toDict()); + const newOutputMessage = new AIMessage(output.text) + const messageToAdd = [newOutputMessage].map((msg) => msg.toDict()) await this.collection.updateOne( { sessionId: id }, { $push: { messages: { $each: messageToAdd } } }, { upsert: true } - ); + ) } } async clearChatMessages(overrideSessionId = ''): Promise { - if (!this.collection) return; + if (!this.collection) return - const id = overrideSessionId ?? this.sessionId; - await this.collection.deleteOne({ sessionId: id }); - await this.clear(); + const id = overrideSessionId ?? this.sessionId + await this.collection.deleteOne({ sessionId: id }) + await this.clear() } } -module.exports = { nodeClass: MongoDB_Memory }; +module.exports = { nodeClass: MongoDB_Memory } From 51388d50577f11b6d6757d1bbeb29e5d1f01db2f Mon Sep 17 00:00:00 2001 From: Ashes47 Date: Sun, 28 Jan 2024 21:48:15 +0530 Subject: [PATCH 17/40] update --- .../nodes/memory/MongoDBMemory/MongoDBMemory.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts index 3c2903f36..7399ad810 100644 --- a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts +++ b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts @@ -5,12 +5,15 @@ import { mapStoredMessageToChatMessage, AIMessage, HumanMessage, BaseMessage } f import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods, MessageType } from '../../../src/Interface' -let mongoClientSingleton = null +let mongoClientSingleton: MongoClient +let mongoUrl: string -const getMongoClient = async (mongoDBConnectUrl) => { - if (!mongoClientSingleton) { - mongoClientSingleton = new MongoClient(mongoDBConnectUrl, { useNewUrlParser: true, useUnifiedTopology: true }) +const getMongoClient = async (newMongoUrl: string) => { + if (!mongoClientSingleton || newMongoUrl !== mongoUrl) { + mongoClientSingleton = new MongoClient(newMongoUrl) + mongoUrl = newMongoUrl await mongoClientSingleton.connect() + return mongoClientSingleton } return mongoClientSingleton } From 1c108f35999a490c1d3727cdfb32736765d62587 Mon Sep 17 00:00:00 2001 From: Ashes47 Date: Sun, 28 Jan 2024 21:51:27 +0530 Subject: [PATCH 18/40] update --- .../nodes/memory/MongoDBMemory/MongoDBMemory.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts index 7399ad810..b7309dcd8 100644 --- a/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts +++ b/packages/components/nodes/memory/MongoDBMemory/MongoDBMemory.ts @@ -9,15 +9,20 @@ let mongoClientSingleton: MongoClient let mongoUrl: string const getMongoClient = async (newMongoUrl: string) => { - if (!mongoClientSingleton || newMongoUrl !== mongoUrl) { + if (!mongoClientSingleton) { + // if client doesn't exists + mongoClientSingleton = new MongoClient(newMongoUrl) + mongoUrl = newMongoUrl + return mongoClientSingleton + } else if (mongoClientSingleton && newMongoUrl !== mongoUrl) { + // if client exists but url changed + mongoClientSingleton.close() mongoClientSingleton = new MongoClient(newMongoUrl) mongoUrl = newMongoUrl - await mongoClientSingleton.connect() return mongoClientSingleton } return mongoClientSingleton } - class MongoDB_Memory implements INode { label: string name: string From 393f9b57c69e1405731f7a9014a6b790713fd772 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 28 Jan 2024 17:18:18 +0000 Subject: [PATCH 19/40] use singleton redis connection --- .../nodes/cache/RedisCache/RedisCache.ts | 43 ++++++++++++- .../cache/RedisCache/RedisEmbeddingsCache.ts | 43 ++++++++++++- .../RedisBackedChatMemory.ts | 61 ++++++++++++------- .../nodes/vectorstores/Qdrant/Qdrant.ts | 7 --- .../nodes/vectorstores/Redis/Redis.ts | 31 ++++++++-- .../vectorstores/Redis/RedisSearchBase.ts | 28 +++++++-- .../vectorstores/Redis/Redis_Existing.ts | 1 - .../nodes/vectorstores/Redis/Redis_Upsert.ts | 1 - 8 files changed, 169 insertions(+), 46 deletions(-) diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index 4e61c239e..c93adf58f 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -1,9 +1,46 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { RedisCache as LangchainRedisCache } from 'langchain/cache/ioredis' -import { Redis } from 'ioredis' +import { Redis, RedisOptions } from 'ioredis' +import { isEqual } from 'lodash' import { Generation, ChatGeneration, StoredGeneration, mapStoredMessageToChatMessage } from 'langchain/schema' import hash from 'object-hash' +let redisClientSingleton: Redis +let redisClientOption: RedisOptions +let redisClientUrl: string + +const getRedisClientbyOption = (option: RedisOptions) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } else if (redisClientSingleton && !isEqual(option, redisClientOption)) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } + return redisClientSingleton +} + +const getRedisClientbyUrl = (url: string) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = new Redis(url) + redisClientUrl = url + return redisClientSingleton + } else if (redisClientSingleton && url !== redisClientUrl) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = new Redis(url) + redisClientUrl = url + return redisClientSingleton + } + return redisClientSingleton +} + class RedisCache implements INode { label: string name: string @@ -60,7 +97,7 @@ class RedisCache implements INode { const tlsOptions = sslEnabled === true ? { tls: { rejectUnauthorized: false } } : {} - client = new Redis({ + client = getRedisClientbyOption({ port: portStr ? parseInt(portStr) : 6379, host, username, @@ -68,7 +105,7 @@ class RedisCache implements INode { ...tlsOptions }) } else { - client = new Redis(redisUrl) + client = getRedisClientbyUrl(redisUrl) } const redisClient = new LangchainRedisCache(client) diff --git a/packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts b/packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts index fe1b4df8a..b74413fe5 100644 --- a/packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts @@ -1,9 +1,46 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' -import { Redis } from 'ioredis' +import { Redis, RedisOptions } from 'ioredis' +import { isEqual } from 'lodash' import { CacheBackedEmbeddings } from 'langchain/embeddings/cache_backed' import { RedisByteStore } from 'langchain/storage/ioredis' import { Embeddings } from 'langchain/embeddings/base' +let redisClientSingleton: Redis +let redisClientOption: RedisOptions +let redisClientUrl: string + +const getRedisClientbyOption = (option: RedisOptions) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } else if (redisClientSingleton && !isEqual(option, redisClientOption)) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } + return redisClientSingleton +} + +const getRedisClientbyUrl = (url: string) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = new Redis(url) + redisClientUrl = url + return redisClientSingleton + } else if (redisClientSingleton && url !== redisClientUrl) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = new Redis(url) + redisClientUrl = url + return redisClientSingleton + } + return redisClientSingleton +} + class RedisEmbeddingsCache implements INode { label: string name: string @@ -75,7 +112,7 @@ class RedisEmbeddingsCache implements INode { const tlsOptions = sslEnabled === true ? { tls: { rejectUnauthorized: false } } : {} - client = new Redis({ + client = getRedisClientbyOption({ port: portStr ? parseInt(portStr) : 6379, host, username, @@ -83,7 +120,7 @@ class RedisEmbeddingsCache implements INode { ...tlsOptions }) } else { - client = new Redis(redisUrl) + client = getRedisClientbyUrl(redisUrl) } ttl ??= '3600' diff --git a/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts b/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts index baf4ea6bb..c54e07b51 100644 --- a/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/RedisBackedChatMemory/RedisBackedChatMemory.ts @@ -1,10 +1,47 @@ -import { Redis } from 'ioredis' +import { Redis, RedisOptions } from 'ioredis' +import { isEqual } from 'lodash' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' import { RedisChatMessageHistory, RedisChatMessageHistoryInput } from 'langchain/stores/message/ioredis' import { mapStoredMessageToChatMessage, BaseMessage, AIMessage, HumanMessage } from 'langchain/schema' import { INode, INodeData, INodeParams, ICommonObject, MessageType, IMessage, MemoryMethods, FlowiseMemory } from '../../../src/Interface' import { convertBaseMessagetoIMessage, getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +let redisClientSingleton: Redis +let redisClientOption: RedisOptions +let redisClientUrl: string + +const getRedisClientbyOption = (option: RedisOptions) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } else if (redisClientSingleton && !isEqual(option, redisClientOption)) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = new Redis(option) + redisClientOption = option + return redisClientSingleton + } + return redisClientSingleton +} + +const getRedisClientbyUrl = (url: string) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = new Redis(url) + redisClientUrl = url + return redisClientSingleton + } else if (redisClientSingleton && url !== redisClientUrl) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = new Redis(url) + redisClientUrl = url + return redisClientSingleton + } + return redisClientSingleton +} + class RedisBackedChatMemory_Memory implements INode { label: string name: string @@ -95,7 +132,7 @@ const initalizeRedis = async (nodeData: INodeData, options: ICommonObject): Prom const tlsOptions = sslEnabled === true ? { tls: { rejectUnauthorized: false } } : {} - client = new Redis({ + client = getRedisClientbyOption({ port: portStr ? parseInt(portStr) : 6379, host, username, @@ -103,7 +140,7 @@ const initalizeRedis = async (nodeData: INodeData, options: ICommonObject): Prom ...tlsOptions }) } else { - client = new Redis(redisUrl) + client = getRedisClientbyUrl(redisUrl) } let obj: RedisChatMessageHistoryInput = { @@ -120,24 +157,6 @@ const initalizeRedis = async (nodeData: INodeData, options: ICommonObject): Prom const redisChatMessageHistory = new RedisChatMessageHistory(obj) - /*redisChatMessageHistory.getMessages = async (): Promise => { - const rawStoredMessages = await client.lrange((redisChatMessageHistory as any).sessionId, windowSize ? -windowSize : 0, -1) - const orderedMessages = rawStoredMessages.reverse().map((message) => JSON.parse(message)) - return orderedMessages.map(mapStoredMessageToChatMessage) - } - - redisChatMessageHistory.addMessage = async (message: BaseMessage): Promise => { - const messageToAdd = [message].map((msg) => msg.toDict()) - await client.lpush((redisChatMessageHistory as any).sessionId, JSON.stringify(messageToAdd[0])) - if (sessionTTL) { - await client.expire((redisChatMessageHistory as any).sessionId, sessionTTL) - } - } - - redisChatMessageHistory.clear = async (): Promise => { - await client.del((redisChatMessageHistory as any).sessionId) - }*/ - const memory = new BufferMemoryExtended({ memoryKey: memoryKey ?? 'chat_history', chatHistory: redisChatMessageHistory, diff --git a/packages/components/nodes/vectorstores/Qdrant/Qdrant.ts b/packages/components/nodes/vectorstores/Qdrant/Qdrant.ts index 1d5f77887..80899942f 100644 --- a/packages/components/nodes/vectorstores/Qdrant/Qdrant.ts +++ b/packages/components/nodes/vectorstores/Qdrant/Qdrant.ts @@ -1,6 +1,5 @@ import { flatten } from 'lodash' import { QdrantClient } from '@qdrant/js-client-rest' -import type { Schemas as QdrantSchemas } from '@qdrant/js-client-rest' import { VectorStoreRetrieverInput } from 'langchain/vectorstores/base' import { Document } from 'langchain/document' import { QdrantVectorStore, QdrantLibArgs } from 'langchain/vectorstores/qdrant' @@ -9,12 +8,6 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' type RetrieverConfig = Partial> -type QdrantSearchResponse = QdrantSchemas['ScoredPoint'] & { - payload: { - metadata: object - content: string - } -} class Qdrant_VectorStores implements INode { label: string diff --git a/packages/components/nodes/vectorstores/Redis/Redis.ts b/packages/components/nodes/vectorstores/Redis/Redis.ts index 49f9e8ffc..0dddf782b 100644 --- a/packages/components/nodes/vectorstores/Redis/Redis.ts +++ b/packages/components/nodes/vectorstores/Redis/Redis.ts @@ -1,5 +1,5 @@ -import { flatten } from 'lodash' -import { createClient, SearchOptions } from 'redis' +import { flatten, isEqual } from 'lodash' +import { createClient, SearchOptions, RedisClientOptions } from 'redis' import { Embeddings } from 'langchain/embeddings/base' import { RedisVectorStore, RedisVectorStoreConfig } from 'langchain/vectorstores/redis' import { Document } from 'langchain/document' @@ -7,6 +7,27 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { escapeAllStrings, escapeSpecialChars, unEscapeSpecialChars } from './utils' +let redisClientSingleton: ReturnType +let redisClientOption: RedisClientOptions + +const getRedisClient = async (option: RedisClientOptions) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = createClient(option) + await redisClientSingleton.connect() + redisClientOption = option + return redisClientSingleton + } else if (redisClientSingleton && !isEqual(option, redisClientOption)) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = createClient(option) + await redisClientSingleton.connect() + redisClientOption = option + return redisClientSingleton + } + return redisClientSingleton +} + class Redis_VectorStores implements INode { label: string name: string @@ -149,8 +170,7 @@ class Redis_VectorStores implements INode { } try { - const redisClient = createClient({ url: redisUrl }) - await redisClient.connect() + const redisClient = await getRedisClient({ url: redisUrl }) const storeConfig: RedisVectorStoreConfig = { redisClient: redisClient, @@ -210,8 +230,7 @@ class Redis_VectorStores implements INode { redisUrl = 'redis://' + username + ':' + password + '@' + host + ':' + portStr } - const redisClient = createClient({ url: redisUrl }) - await redisClient.connect() + const redisClient = await getRedisClient({ url: redisUrl }) const storeConfig: RedisVectorStoreConfig = { redisClient: redisClient, diff --git a/packages/components/nodes/vectorstores/Redis/RedisSearchBase.ts b/packages/components/nodes/vectorstores/Redis/RedisSearchBase.ts index b6aa6ebb0..e87b49f9c 100644 --- a/packages/components/nodes/vectorstores/Redis/RedisSearchBase.ts +++ b/packages/components/nodes/vectorstores/Redis/RedisSearchBase.ts @@ -7,13 +7,34 @@ import { INodeOutputsValue, INodeParams } from '../../../src' - import { Embeddings } from 'langchain/embeddings/base' import { VectorStore } from 'langchain/vectorstores/base' import { Document } from 'langchain/document' -import { createClient, SearchOptions } from 'redis' +import { createClient, SearchOptions, RedisClientOptions } from 'redis' import { RedisVectorStore } from 'langchain/vectorstores/redis' import { escapeSpecialChars, unEscapeSpecialChars } from './utils' +import { isEqual } from 'lodash' + +let redisClientSingleton: ReturnType +let redisClientOption: RedisClientOptions + +const getRedisClient = async (option: RedisClientOptions) => { + if (!redisClientSingleton) { + // if client doesn't exists + redisClientSingleton = createClient(option) + await redisClientSingleton.connect() + redisClientOption = option + return redisClientSingleton + } else if (redisClientSingleton && !isEqual(option, redisClientOption)) { + // if client exists but option changed + redisClientSingleton.quit() + redisClientSingleton = createClient(option) + await redisClientSingleton.connect() + redisClientOption = option + return redisClientSingleton + } + return redisClientSingleton +} export abstract class RedisSearchBase { label: string @@ -141,8 +162,7 @@ export abstract class RedisSearchBase { redisUrl = 'redis://' + username + ':' + password + '@' + host + ':' + portStr } - this.redisClient = createClient({ url: redisUrl }) - await this.redisClient.connect() + this.redisClient = await getRedisClient({ url: redisUrl }) const vectorStore = await this.constructVectorStore(embeddings, indexName, replaceIndex, docs) if (!contentKey || contentKey === '') contentKey = 'content' diff --git a/packages/components/nodes/vectorstores/Redis/Redis_Existing.ts b/packages/components/nodes/vectorstores/Redis/Redis_Existing.ts index e8848d338..6f2ec9b32 100644 --- a/packages/components/nodes/vectorstores/Redis/Redis_Existing.ts +++ b/packages/components/nodes/vectorstores/Redis/Redis_Existing.ts @@ -3,7 +3,6 @@ import { Embeddings } from 'langchain/embeddings/base' import { VectorStore } from 'langchain/vectorstores/base' import { RedisVectorStore, RedisVectorStoreConfig } from 'langchain/vectorstores/redis' import { Document } from 'langchain/document' - import { RedisSearchBase } from './RedisSearchBase' class RedisExisting_VectorStores extends RedisSearchBase implements INode { diff --git a/packages/components/nodes/vectorstores/Redis/Redis_Upsert.ts b/packages/components/nodes/vectorstores/Redis/Redis_Upsert.ts index 4da58eaff..c43948247 100644 --- a/packages/components/nodes/vectorstores/Redis/Redis_Upsert.ts +++ b/packages/components/nodes/vectorstores/Redis/Redis_Upsert.ts @@ -1,7 +1,6 @@ import { ICommonObject, INode, INodeData } from '../../../src/Interface' import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' - import { flatten } from 'lodash' import { RedisSearchBase } from './RedisSearchBase' import { VectorStore } from 'langchain/vectorstores/base' From 74f7cd6e311ebd87699461537ce407a0a3760d20 Mon Sep 17 00:00:00 2001 From: niztal Date: Sun, 28 Jan 2024 23:34:21 +0200 Subject: [PATCH 20/40] fix bug settings.json not found on upsert --- packages/server/src/DataSource.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/server/src/DataSource.ts b/packages/server/src/DataSource.ts index 762315ac9..9ea391ef6 100644 --- a/packages/server/src/DataSource.ts +++ b/packages/server/src/DataSource.ts @@ -1,5 +1,6 @@ import 'reflect-metadata' import path from 'path' +import * as fs from 'fs' import { DataSource } from 'typeorm' import { getUserHome } from './utils' import { entities } from './database/entities' @@ -10,10 +11,14 @@ import { postgresMigrations } from './database/migrations/postgres' let appDataSource: DataSource export const init = async (): Promise => { - let homePath + let homePath; + let flowisePath = path.join(getUserHome(), '.flowise'); + if (!fs.existsSync(flowisePath)) { + fs.mkdirSync(flowisePath); + } switch (process.env.DATABASE_TYPE) { case 'sqlite': - homePath = process.env.DATABASE_PATH ?? path.join(getUserHome(), '.flowise') + homePath = process.env.DATABASE_PATH ?? flowisePath; appDataSource = new DataSource({ type: 'sqlite', database: path.resolve(homePath, 'database.sqlite'), @@ -54,7 +59,7 @@ export const init = async (): Promise => { }) break default: - homePath = process.env.DATABASE_PATH ?? path.join(getUserHome(), '.flowise') + homePath = process.env.DATABASE_PATH ?? flowisePath; appDataSource = new DataSource({ type: 'sqlite', database: path.resolve(homePath, 'database.sqlite'), From 30ff29afc7113efdb49b1f8bf37e1a161c179467 Mon Sep 17 00:00:00 2001 From: niztal Date: Sun, 28 Jan 2024 23:49:42 +0200 Subject: [PATCH 21/40] fix lint errors --- packages/server/src/DataSource.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/server/src/DataSource.ts b/packages/server/src/DataSource.ts index 9ea391ef6..a23b4ce27 100644 --- a/packages/server/src/DataSource.ts +++ b/packages/server/src/DataSource.ts @@ -11,14 +11,14 @@ import { postgresMigrations } from './database/migrations/postgres' let appDataSource: DataSource export const init = async (): Promise => { - let homePath; - let flowisePath = path.join(getUserHome(), '.flowise'); + let homePath + let flowisePath = path.join(getUserHome(), '.flowise') if (!fs.existsSync(flowisePath)) { - fs.mkdirSync(flowisePath); + fs.mkdirSync(flowisePath) } switch (process.env.DATABASE_TYPE) { case 'sqlite': - homePath = process.env.DATABASE_PATH ?? flowisePath; + homePath = process.env.DATABASE_PATH ?? flowisePath appDataSource = new DataSource({ type: 'sqlite', database: path.resolve(homePath, 'database.sqlite'), @@ -59,7 +59,7 @@ export const init = async (): Promise => { }) break default: - homePath = process.env.DATABASE_PATH ?? flowisePath; + homePath = process.env.DATABASE_PATH ?? flowisePath appDataSource = new DataSource({ type: 'sqlite', database: path.resolve(homePath, 'database.sqlite'), From 71f456af90ab0d9855f9a1f3207e6589decc034b Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Thu, 25 Jan 2024 11:00:58 -0500 Subject: [PATCH 22/40] Switched to specifying Airtable fields to include rather than exclude - this helps reduce the amount of data fetched by the DocumentLoader when there are massive numbers of fields in an Airtable table. --- .../documentloaders/Airtable/Airtable.ts | 67 +++++++++++-------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 0f212a0a8..78ad7a66f 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -65,13 +65,13 @@ class Airtable_DocumentLoaders implements INode { optional: true }, { - label: 'Exclude Field Names', - name: 'excludeFieldNames', + label: 'Fields', + name: 'fields', type: 'string', - placeholder: 'Name, Assignee', + placeholder: 'Name, Assignee, fld1u0qUz0SoOQ9Gg, fldew39v6LBN5CjUl', optional: true, additionalParams: true, - description: 'Comma-separated list of field names to exclude' + description: 'Comma-separated list of field names or IDs to include. Use field IDs if field names contain commas.' }, { label: 'Return All', @@ -102,7 +102,8 @@ class Airtable_DocumentLoaders implements INode { const baseId = nodeData.inputs?.baseId as string const tableId = nodeData.inputs?.tableId as string const viewId = nodeData.inputs?.viewId as string - const excludeFieldNames = nodeData.inputs?.excludeFieldNames as string + const fieldsInput = nodeData.inputs?.fields as string + const fields = fieldsInput ? fieldsInput.split(',').map((field) => field.trim()) : [] const returnAll = nodeData.inputs?.returnAll as boolean const limit = nodeData.inputs?.limit as string const textSplitter = nodeData.inputs?.textSplitter as TextSplitter @@ -115,7 +116,7 @@ class Airtable_DocumentLoaders implements INode { baseId, tableId, viewId, - excludeFieldNames: excludeFieldNames ? excludeFieldNames.split(',').map((id) => id.trim()) : [], + fields, returnAll, accessToken, limit: limit ? parseInt(limit, 10) : 100 @@ -156,7 +157,7 @@ interface AirtableLoaderParams { tableId: string accessToken: string viewId?: string - excludeFieldNames?: string[] + fields?: string[] limit?: number returnAll?: boolean } @@ -179,7 +180,7 @@ class AirtableLoader extends BaseDocumentLoader { public readonly viewId?: string - public readonly excludeFieldNames: string[] + public readonly fields: string[] public readonly accessToken: string @@ -187,12 +188,12 @@ class AirtableLoader extends BaseDocumentLoader { public readonly returnAll: boolean - constructor({ baseId, tableId, viewId, excludeFieldNames = [], accessToken, limit = 100, returnAll = false }: AirtableLoaderParams) { + constructor({ baseId, tableId, viewId, fields = [], accessToken, limit = 100, returnAll = false }: AirtableLoaderParams) { super() this.baseId = baseId this.tableId = tableId this.viewId = viewId - this.excludeFieldNames = excludeFieldNames + this.fields = fields this.accessToken = accessToken this.limit = limit this.returnAll = returnAll @@ -205,14 +206,14 @@ class AirtableLoader extends BaseDocumentLoader { return this.loadLimit() } - protected async fetchAirtableData(url: string, params: ICommonObject): Promise { + protected async fetchAirtableData(url: string, data: any): Promise { try { const headers = { Authorization: `Bearer ${this.accessToken}`, 'Content-Type': 'application/json', Accept: 'application/json' } - const response = await axios.get(url, { params, headers }) + const response = await axios.get(url, data, { headers }) return response.data } catch (error) { throw new Error(`Failed to fetch ${url} from Airtable: ${error}`) @@ -222,12 +223,6 @@ class AirtableLoader extends BaseDocumentLoader { private createDocumentFromPage(page: AirtableLoaderPage): Document { // Generate the URL const pageUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}/${page.id}` - const fields = { ...page.fields } - - // Exclude any specified fields - this.excludeFieldNames.forEach((id) => { - delete fields[id] - }) // Return a langchain document return new Document({ @@ -239,24 +234,40 @@ class AirtableLoader extends BaseDocumentLoader { } private async loadLimit(): Promise { - const params = { maxRecords: this.limit, view: this.viewId } - const data = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, params) - if (data.records.length === 0) { + const data = { + maxRecords: this.limit, + view: this.viewId + } + + if (this.fields.length > 0) { + data.fields = this.fields + } + + const response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, data) + if (response.records.length === 0) { return [] } - return data.records.map((page) => this.createDocumentFromPage(page)) + return response.records.map((page) => this.createDocumentFromPage(page)) } private async loadAll(): Promise { - const params: ICommonObject = { pageSize: 100, view: this.viewId } - let data: AirtableLoaderResponse + const data = { + pageSize: 100, + view: this.viewId + } + + if (this.fields.length > 0) { + data.fields = this.fields + } + + let response: AirtableLoaderResponse let returnPages: AirtableLoaderPage[] = [] do { - data = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, params) - returnPages.push.apply(returnPages, data.records) - params.offset = data.offset - } while (data.offset !== undefined) + response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, data) + returnPages.push.apply(returnPages, response.records) + params.offset = response.offset + } while (response.offset !== undefined) return returnPages.map((page) => this.createDocumentFromPage(page)) } } From ae64854baedca9c6f224136578bb87a1df93afa4 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Thu, 25 Jan 2024 11:29:06 -0500 Subject: [PATCH 23/40] Fixing a bunch of build errors --- .../nodes/documentloaders/Airtable/Airtable.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 78ad7a66f..6fdb070aa 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -162,6 +162,12 @@ interface AirtableLoaderParams { returnAll?: boolean } +interface AirtableLoaderRequest { + maxRecords: number + view: string | undefined + fields?: string[] +} + interface AirtableLoaderResponse { records: AirtableLoaderPage[] offset?: string @@ -213,7 +219,7 @@ class AirtableLoader extends BaseDocumentLoader { 'Content-Type': 'application/json', Accept: 'application/json' } - const response = await axios.get(url, data, { headers }) + const response = await axios.post(url, data, { headers }) return response.data } catch (error) { throw new Error(`Failed to fetch ${url} from Airtable: ${error}`) @@ -226,7 +232,7 @@ class AirtableLoader extends BaseDocumentLoader { // Return a langchain document return new Document({ - pageContent: JSON.stringify(fields, null, 2), + pageContent: JSON.stringify(page.fields, null, 2), metadata: { url: pageUrl } @@ -234,7 +240,7 @@ class AirtableLoader extends BaseDocumentLoader { } private async loadLimit(): Promise { - const data = { + let data: AirtableLoaderRequest = { maxRecords: this.limit, view: this.viewId } @@ -251,7 +257,7 @@ class AirtableLoader extends BaseDocumentLoader { } private async loadAll(): Promise { - const data = { + let data: AirtableLoaderRequest = { pageSize: 100, view: this.viewId } From 1a7cb5a010039f714fbe8e117a9875985866f2f4 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Thu, 25 Jan 2024 11:43:56 -0500 Subject: [PATCH 24/40] Fixing more build errors --- .../components/nodes/documentloaders/Airtable/Airtable.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 6fdb070aa..de913b90e 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -166,6 +166,7 @@ interface AirtableLoaderRequest { maxRecords: number view: string | undefined fields?: string[] + offset?: string } interface AirtableLoaderResponse { @@ -258,7 +259,7 @@ class AirtableLoader extends BaseDocumentLoader { private async loadAll(): Promise { let data: AirtableLoaderRequest = { - pageSize: 100, + pageSize: this.limit, view: this.viewId } @@ -272,7 +273,7 @@ class AirtableLoader extends BaseDocumentLoader { do { response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, data) returnPages.push.apply(returnPages, response.records) - params.offset = response.offset + data.offset = response.offset } while (response.offset !== undefined) return returnPages.map((page) => this.createDocumentFromPage(page)) } From 72ec7878b609e013f3a7b17b3875beab2f936d0e Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Thu, 25 Jan 2024 12:08:52 -0500 Subject: [PATCH 25/40] Added more error checking and also fixed yet more build errors --- .../nodes/documentloaders/Airtable/Airtable.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index de913b90e..4558edb5c 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -124,6 +124,10 @@ class Airtable_DocumentLoaders implements INode { const loader = new AirtableLoader(airtableOptions) + if (!baseId || !tableId) { + throw new Error('Base ID and Table ID must be provided.') + } + let docs = [] if (textSplitter) { @@ -213,7 +217,7 @@ class AirtableLoader extends BaseDocumentLoader { return this.loadLimit() } - protected async fetchAirtableData(url: string, data: any): Promise { + protected async fetchAirtableData(url: string, data: AirtableLoaderRequest): Promise { try { const headers = { Authorization: `Bearer ${this.accessToken}`, @@ -223,7 +227,11 @@ class AirtableLoader extends BaseDocumentLoader { const response = await axios.post(url, data, { headers }) return response.data } catch (error) { - throw new Error(`Failed to fetch ${url} from Airtable: ${error}`) + if (axios.isAxiosError(error)) { + throw new Error(`Failed to fetch ${url} from Airtable: ${error.message}, status: ${error.response?.status}`) + } else { + throw new Error(`Failed to fetch ${url} from Airtable: ${error}`) + } } } @@ -259,7 +267,7 @@ class AirtableLoader extends BaseDocumentLoader { private async loadAll(): Promise { let data: AirtableLoaderRequest = { - pageSize: this.limit, + maxRecords: this.limit, view: this.viewId } @@ -272,7 +280,7 @@ class AirtableLoader extends BaseDocumentLoader { do { response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, data) - returnPages.push.apply(returnPages, response.records) + returnPages.push(...response.records) data.offset = response.offset } while (response.offset !== undefined) return returnPages.map((page) => this.createDocumentFromPage(page)) From 8ae848110eb98726e30994f4442fa9e4c5544e8a Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Thu, 25 Jan 2024 21:36:42 -0500 Subject: [PATCH 26/40] Clarifying the description for the optional fields param --- .../components/nodes/documentloaders/Airtable/Airtable.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 4558edb5c..ed1572647 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -65,13 +65,13 @@ class Airtable_DocumentLoaders implements INode { optional: true }, { - label: 'Fields', + label: 'Include Only Fields', name: 'fields', type: 'string', placeholder: 'Name, Assignee, fld1u0qUz0SoOQ9Gg, fldew39v6LBN5CjUl', optional: true, additionalParams: true, - description: 'Comma-separated list of field names or IDs to include. Use field IDs if field names contain commas.' + description: 'Comma-separated list of field names or IDs to include. If empty, then ALL fields are used. Use field IDs if field names contain commas.' }, { label: 'Return All', From 456dfabc6febea31ab11ce1bab22a4b51ac70c8a Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Fri, 26 Jan 2024 13:48:09 -0500 Subject: [PATCH 27/40] For some reason, Airtable doesn't like the POST operations, so I need to add logging to figure out why this happens --- .../components/nodes/documentloaders/Airtable/Airtable.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index ed1572647..d0ed3b44a 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -71,7 +71,8 @@ class Airtable_DocumentLoaders implements INode { placeholder: 'Name, Assignee, fld1u0qUz0SoOQ9Gg, fldew39v6LBN5CjUl', optional: true, additionalParams: true, - description: 'Comma-separated list of field names or IDs to include. If empty, then ALL fields are used. Use field IDs if field names contain commas.' + description: + 'Comma-separated list of field names or IDs to include. If empty, then ALL fields are used. Use field IDs if field names contain commas.' }, { label: 'Return All', @@ -224,12 +225,15 @@ class AirtableLoader extends BaseDocumentLoader { 'Content-Type': 'application/json', Accept: 'application/json' } + console.log('Sending request to Airtable with data: ', data) const response = await axios.post(url, data, { headers }) return response.data } catch (error) { if (axios.isAxiosError(error)) { + console.error('Error response from Airtable:', error.response?.data) throw new Error(`Failed to fetch ${url} from Airtable: ${error.message}, status: ${error.response?.status}`) } else { + console.error('An unexpected error occurred:', error) throw new Error(`Failed to fetch ${url} from Airtable: ${error}`) } } From 3b788e42e1520c193a909001faa8793a35420caa Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Fri, 26 Jan 2024 15:03:30 -0500 Subject: [PATCH 28/40] When you switch from GET to POST, you're supposed to adjust the Airtable URL to use the /listRecords endpoint. I didn't RTFM clearly. This is currently documented here: https://support.airtable.com/docs/enforcement-of-url-length-limit-for-web-api-requests --- .../components/nodes/documentloaders/Airtable/Airtable.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index d0ed3b44a..7d5e8ad06 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -262,7 +262,7 @@ class AirtableLoader extends BaseDocumentLoader { data.fields = this.fields } - const response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, data) + const response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}/listRecords`, data) if (response.records.length === 0) { return [] } @@ -283,7 +283,7 @@ class AirtableLoader extends BaseDocumentLoader { let returnPages: AirtableLoaderPage[] = [] do { - response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}`, data) + response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}/listRecords`, data) returnPages.push(...response.records) data.offset = response.offset } while (response.offset !== undefined) From 2237b1ab165d6ff0acd6252b0be7c1e31591a8ec Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Fri, 26 Jan 2024 17:15:39 -0500 Subject: [PATCH 29/40] Fix worked, removing debug logging, and bumped node version. --- .../components/nodes/documentloaders/Airtable/Airtable.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 7d5e8ad06..76d6e3494 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -20,7 +20,7 @@ class Airtable_DocumentLoaders implements INode { constructor() { this.label = 'Airtable' this.name = 'airtable' - this.version = 2.0 + this.version = 3.0 this.type = 'Document' this.icon = 'airtable.svg' this.category = 'Document Loaders' @@ -225,15 +225,12 @@ class AirtableLoader extends BaseDocumentLoader { 'Content-Type': 'application/json', Accept: 'application/json' } - console.log('Sending request to Airtable with data: ', data) const response = await axios.post(url, data, { headers }) return response.data } catch (error) { if (axios.isAxiosError(error)) { - console.error('Error response from Airtable:', error.response?.data) throw new Error(`Failed to fetch ${url} from Airtable: ${error.message}, status: ${error.response?.status}`) } else { - console.error('An unexpected error occurred:', error) throw new Error(`Failed to fetch ${url} from Airtable: ${error}`) } } From 9b71f683fffe916baced5693cbe0f070dd043d12 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sat, 27 Jan 2024 13:58:20 -0500 Subject: [PATCH 30/40] Support pagination even in loadLimit(), so that if a user wants to load more than 100 records but not all of them, they can. Currently, there's a bug where the document loader doesn't work on loading more than 100 records because of internal Airtable API limitations. The Airtable API can only fetch up to 100 records per call - anything more than that requires pagination. --- .../documentloaders/Airtable/Airtable.ts | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 76d6e3494..011975a72 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -251,7 +251,7 @@ class AirtableLoader extends BaseDocumentLoader { private async loadLimit(): Promise { let data: AirtableLoaderRequest = { - maxRecords: this.limit, + maxRecords: Math.min(this.limit, 100), // Airtable only returns up to 100 records per request view: this.viewId } @@ -259,11 +259,25 @@ class AirtableLoader extends BaseDocumentLoader { data.fields = this.fields } - const response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}/listRecords`, data) - if (response.records.length === 0) { - return [] + let response: AirtableLoaderResponse + let returnPages: AirtableLoaderPage[] = [] + + // Paginate if the user specifies a limit > 100 (like 200) but not return all. + do { + response = await this.fetchAirtableData(`https://api.airtable.com/v0/${this.baseId}/${this.tableId}/listRecords`, data) + returnPages.push(...response.records) + data.offset = response.offset + + // Stop if we have fetched enough records + if (returnPages.length >= this.limit) break + } while (response.offset !== undefined) + + // Truncate array to the limit if necessary + if (returnPages.length > this.limit) { + returnPages.length = this.limit } - return response.records.map((page) => this.createDocumentFromPage(page)) + + return returnPages.map((page) => this.createDocumentFromPage(page)) } private async loadAll(): Promise { From dc39d7e2bec837d863bde0c8b8b52fcdb1b37078 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sat, 27 Jan 2024 16:33:16 -0500 Subject: [PATCH 31/40] So Airtable API expects a maxRecords value to be the total set of records you want across multiple API calls. If the maxRecords is greater than 100, then it will provide pagination hints accordingly. --- packages/components/nodes/documentloaders/Airtable/Airtable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 011975a72..90a7ba03f 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -251,7 +251,7 @@ class AirtableLoader extends BaseDocumentLoader { private async loadLimit(): Promise { let data: AirtableLoaderRequest = { - maxRecords: Math.min(this.limit, 100), // Airtable only returns up to 100 records per request + maxRecords: this.limit, view: this.viewId } From 37945fc998cd1e2818756a7877ffb4613be46094 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sat, 27 Jan 2024 21:25:43 -0800 Subject: [PATCH 32/40] The loadAll() function should ignore any maxRecords specified, because the intention is the load *all* of the records. Also, marking both the Return All and Limit params as optional, so as to not confuse the user. Making them both required adds a lot of confusion that doesn't make sense. Ideally, the user either specifies Return All OR specifies the Limit value but not BOTH. It seems there's no way to define "conditional requirements" in Flowise params, so it's better to make both params optional. --- packages/components/nodes/documentloaders/Airtable/Airtable.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 90a7ba03f..8845bbe06 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -78,6 +78,7 @@ class Airtable_DocumentLoaders implements INode { label: 'Return All', name: 'returnAll', type: 'boolean', + optional: true, default: true, additionalParams: true, description: 'If all results should be returned or only up to a given limit' @@ -86,6 +87,7 @@ class Airtable_DocumentLoaders implements INode { label: 'Limit', name: 'limit', type: 'number', + optional: true, default: 100, additionalParams: true, description: 'Number of results to return' @@ -282,7 +284,6 @@ class AirtableLoader extends BaseDocumentLoader { private async loadAll(): Promise { let data: AirtableLoaderRequest = { - maxRecords: this.limit, view: this.viewId } From 66eef8463315a5f045b428478abf71b1b53b9996 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sat, 27 Jan 2024 21:40:05 -0800 Subject: [PATCH 33/40] Forgot to make maxRecords optional now --- packages/components/nodes/documentloaders/Airtable/Airtable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index 8845bbe06..b0478100c 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -170,7 +170,7 @@ interface AirtableLoaderParams { } interface AirtableLoaderRequest { - maxRecords: number + maxRecords?: number view: string | undefined fields?: string[] offset?: string From b960f061ebbedaa2cbc0b1cdc802999ab9a948df Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sun, 28 Jan 2024 08:21:02 -0800 Subject: [PATCH 34/40] Clarifying that the Limit value is ignored when Return All is set to true. --- packages/components/nodes/documentloaders/Airtable/Airtable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/documentloaders/Airtable/Airtable.ts b/packages/components/nodes/documentloaders/Airtable/Airtable.ts index b0478100c..148152972 100644 --- a/packages/components/nodes/documentloaders/Airtable/Airtable.ts +++ b/packages/components/nodes/documentloaders/Airtable/Airtable.ts @@ -90,7 +90,7 @@ class Airtable_DocumentLoaders implements INode { optional: true, default: 100, additionalParams: true, - description: 'Number of results to return' + description: 'Number of results to return. Ignored when Return All is enabled.' }, { label: 'Metadata', From 905c9fc2bed208c7cf5327b077c941533eac8157 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sun, 28 Jan 2024 20:48:08 -0800 Subject: [PATCH 35/40] Reverting version bump --- .../nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index a459a8ec3..9b7b724a2 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -19,7 +19,7 @@ class AzureChatOpenAI_ChatModels implements INode { constructor() { this.label = 'Azure ChatOpenAI' this.name = 'azureChatOpenAI' - this.version = 2.1 + this.version = 2.0 this.type = 'AzureChatOpenAI' this.icon = 'Azure.svg' this.category = 'Chat Models' From 9f4619e40852b470dc83af88c0f55e2403ca0630 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sun, 28 Jan 2024 21:52:40 -0800 Subject: [PATCH 36/40] Switching default batch size from 1 to 100 in order to support higher volume of document loading into vector stores before timing out. --- .../embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts b/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts index b70caa4c2..75897e6c2 100644 --- a/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts +++ b/packages/components/nodes/embeddings/AzureOpenAIEmbedding/AzureOpenAIEmbedding.ts @@ -35,7 +35,7 @@ class AzureOpenAIEmbedding_Embeddings implements INode { label: 'Batch Size', name: 'batchSize', type: 'number', - default: '1', + default: '100', optional: true, additionalParams: true }, From 63665b37ce346f2f1f98737fcc1d7fde3d3a7560 Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Sun, 28 Jan 2024 21:58:04 -0800 Subject: [PATCH 37/40] Switching Redis TTL from EX to PX to match TTL in milliseconds (as specified in the input param). --- packages/components/nodes/cache/RedisCache/RedisCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index c93adf58f..cf7b43c92 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -131,7 +131,7 @@ class RedisCache implements INode { for (let i = 0; i < value.length; i += 1) { const key = getCacheKey(prompt, llmKey, String(i)) if (ttl) { - await client.set(key, JSON.stringify(serializeGeneration(value[i])), 'EX', parseInt(ttl, 10)) + await client.set(key, JSON.stringify(serializeGeneration(value[i])), 'PX', parseInt(ttl, 10)) } else { await client.set(key, JSON.stringify(serializeGeneration(value[i]))) } From 4d6881b506cb19695769550383e88818fbbaee73 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 30 Jan 2024 14:12:55 +0000 Subject: [PATCH 38/40] add return source documens to retriever tool --- .../OpenAIFunctionAgent.ts | 12 ++++++-- .../CustomListOutputParser.ts | 14 ++++++---- .../tools/RetrieverTool/RetrieverTool.ts | 28 +++++++++++++++++-- packages/components/src/agents.ts | 25 ++++++++++++++++- .../Conversational Retrieval Agent.json | 10 ++++++- packages/server/src/index.ts | 11 +++++++- 6 files changed, 86 insertions(+), 14 deletions(-) diff --git a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts index c21c887aa..9c25b2a9a 100644 --- a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts +++ b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts @@ -64,7 +64,7 @@ class OpenAIFunctionAgent_Agents implements INode { return prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }, options.chatHistory) } - async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { + async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { const memory = nodeData.inputs?.memory as FlowiseMemory const executor = prepareAgent(nodeData, { sessionId: this.sessionId, chatId: options.chatId, input }, options.chatHistory) @@ -72,12 +72,20 @@ class OpenAIFunctionAgent_Agents implements INode { const callbacks = await additionalCallbacks(nodeData, options) let res: ChainValues = {} + let sourceDocuments: ICommonObject[] = [] if (options.socketIO && options.socketIOClientId) { const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId) res = await executor.invoke({ input }, { callbacks: [loggerHandler, handler, ...callbacks] }) + if (res.sourceDocuments) { + options.socketIO.to(options.socketIOClientId).emit('sourceDocuments', flatten(res.sourceDocuments)) + sourceDocuments = res.sourceDocuments + } } else { res = await executor.invoke({ input }, { callbacks: [loggerHandler, ...callbacks] }) + if (res.sourceDocuments) { + sourceDocuments = res.sourceDocuments + } } await memory.addChatMessages( @@ -94,7 +102,7 @@ class OpenAIFunctionAgent_Agents implements INode { this.sessionId ) - return res?.output + return sourceDocuments.length ? { text: res?.output, sourceDocuments: flatten(sourceDocuments) } : res?.output } } diff --git a/packages/components/nodes/outputparsers/CustomListOutputParser/CustomListOutputParser.ts b/packages/components/nodes/outputparsers/CustomListOutputParser/CustomListOutputParser.ts index d420a88d9..1e44acdb9 100644 --- a/packages/components/nodes/outputparsers/CustomListOutputParser/CustomListOutputParser.ts +++ b/packages/components/nodes/outputparsers/CustomListOutputParser/CustomListOutputParser.ts @@ -29,16 +29,17 @@ class CustomListOutputParser implements INode { label: 'Length', name: 'length', type: 'number', - default: 5, step: 1, - description: 'Number of values to return' + description: 'Number of values to return', + optional: true }, { label: 'Separator', name: 'separator', type: 'string', description: 'Separator between values', - default: ',' + default: ',', + optional: true }, { label: 'Autofix', @@ -54,10 +55,11 @@ class CustomListOutputParser implements INode { const separator = nodeData.inputs?.separator as string const lengthStr = nodeData.inputs?.length as string const autoFix = nodeData.inputs?.autofixParser as boolean - let length = 5 - if (lengthStr) length = parseInt(lengthStr, 10) - const parser = new LangchainCustomListOutputParser({ length: length, separator: separator }) + const parser = new LangchainCustomListOutputParser({ + length: lengthStr ? parseInt(lengthStr, 10) : undefined, + separator: separator + }) Object.defineProperty(parser, 'autoFix', { enumerable: true, configurable: true, diff --git a/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts b/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts index cc74a015c..4e4a4af8a 100644 --- a/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts +++ b/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts @@ -1,8 +1,11 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { DynamicTool } from 'langchain/tools' -import { createRetrieverTool } from 'langchain/agents/toolkits' +import { DynamicStructuredTool } from '@langchain/core/tools' +import { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager' import { BaseRetriever } from 'langchain/schema/retriever' +import { z } from 'zod' +import { SOURCE_DOCUMENTS_PREFIX } from '../../../src/agents' class Retriever_Tools implements INode { label: string @@ -19,7 +22,7 @@ class Retriever_Tools implements INode { constructor() { this.label = 'Retriever Tool' this.name = 'retrieverTool' - this.version = 1.0 + this.version = 2.0 this.type = 'RetrieverTool' this.icon = 'retrievertool.svg' this.category = 'Tools' @@ -44,6 +47,12 @@ class Retriever_Tools implements INode { label: 'Retriever', name: 'retriever', type: 'BaseRetriever' + }, + { + label: 'Return Source Documents', + name: 'returnSourceDocuments', + type: 'boolean', + optional: true } ] } @@ -52,12 +61,25 @@ class Retriever_Tools implements INode { const name = nodeData.inputs?.name as string const description = nodeData.inputs?.description as string const retriever = nodeData.inputs?.retriever as BaseRetriever + const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean - const tool = createRetrieverTool(retriever, { + const input = { name, description + } + + const func = async ({ input }: { input: string }, runManager?: CallbackManagerForToolRun) => { + const docs = await retriever.getRelevantDocuments(input, runManager?.getChild('retriever')) + const content = docs.map((doc) => doc.pageContent).join('\n\n') + const sourceDocuments = JSON.stringify(docs) + return returnSourceDocuments ? content + SOURCE_DOCUMENTS_PREFIX + sourceDocuments : content + } + + const schema = z.object({ + input: z.string().describe('query to look up in retriever') }) + const tool = new DynamicStructuredTool({ ...input, func, schema }) return tool } } diff --git a/packages/components/src/agents.ts b/packages/components/src/agents.ts index 5e241d505..ab08097b0 100644 --- a/packages/components/src/agents.ts +++ b/packages/components/src/agents.ts @@ -1,5 +1,6 @@ +import { flatten } from 'lodash' import { AgentExecutorInput, BaseSingleActionAgent, BaseMultiActionAgent, RunnableAgent, StoppingMethod } from 'langchain/agents' -import { ChainValues, AgentStep, AgentFinish, AgentAction, BaseMessage, FunctionMessage, AIMessage } from 'langchain/schema' +import { ChainValues, AgentStep, AgentAction, BaseMessage, FunctionMessage, AIMessage } from 'langchain/schema' import { OutputParserException } from 'langchain/schema/output_parser' import { CallbackManager, CallbackManagerForChainRun, Callbacks } from 'langchain/callbacks' import { ToolInputParsingException, Tool } from '@langchain/core/tools' @@ -7,6 +8,11 @@ import { Runnable } from 'langchain/schema/runnable' import { BaseChain, SerializedLLMChain } from 'langchain/chains' import { Serializable } from '@langchain/core/load/serializable' +export const SOURCE_DOCUMENTS_PREFIX = '\n\n----FLOWISE_SOURCE_DOCUMENTS----\n\n' +type AgentFinish = { + returnValues: Record + log: string +} type AgentExecutorOutput = ChainValues interface AgentExecutorIteratorInput { @@ -315,10 +321,12 @@ export class AgentExecutor extends BaseChain { const steps: AgentStep[] = [] let iterations = 0 + let sourceDocuments: Array = [] const getOutput = async (finishStep: AgentFinish): Promise => { const { returnValues } = finishStep const additional = await this.agent.prepareForOutput(returnValues, steps) + if (sourceDocuments.length) additional.sourceDocuments = flatten(sourceDocuments) if (this.returnIntermediateSteps) { return { ...returnValues, intermediateSteps: steps, ...additional } @@ -406,6 +414,17 @@ export class AgentExecutor extends BaseChain { return { action, observation: observation ?? '' } } } + if (observation?.includes(SOURCE_DOCUMENTS_PREFIX)) { + const observationArray = observation.split(SOURCE_DOCUMENTS_PREFIX) + observation = observationArray[0] + const docs = observationArray[1] + try { + const parsedDocs = JSON.parse(docs) + sourceDocuments.push(parsedDocs) + } catch (e) { + console.error('Error parsing source documents from tool') + } + } return { action, observation: observation ?? '' } }) ) @@ -500,6 +519,10 @@ export class AgentExecutor extends BaseChain { chatId: this.chatId, input: this.input }) + if (observation?.includes(SOURCE_DOCUMENTS_PREFIX)) { + const observationArray = observation.split(SOURCE_DOCUMENTS_PREFIX) + observation = observationArray[0] + } } catch (e) { if (e instanceof ToolInputParsingException) { if (this.handleParsingErrors === true) { diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json index 810c2b354..40c689f50 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json @@ -217,6 +217,13 @@ "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": [ @@ -230,7 +237,8 @@ "inputs": { "name": "search_website", "description": "Searches and return documents regarding Jane - a culinary institution that offers top quality coffee, pastries, breakfast, lunch, and a variety of baked goods. They have multiple locations, including Jane on Fillmore, Jane on Larkin, Jane the Bakery, Toy Boat By Jane, and Little Jane on Grant. They emphasize healthy eating with a focus on flavor and quality ingredients. They bake everything in-house and work with local suppliers to source ingredients directly from farmers. They also offer catering services and delivery options.", - "retriever": "{{pinecone_0.data.instance}}" + "retriever": "{{pinecone_0.data.instance}}", + "returnSourceDocuments": true }, "outputAnchors": [ { diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index b0bb06f55..045e40dd7 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -473,6 +473,8 @@ export class App { const endingNodes = nodes.filter((nd) => endingNodeIds.includes(nd.id)) let isStreaming = false + let isEndingNodeExists = endingNodes.find((node) => node.data?.outputs?.output === 'EndingNode') + for (const endingNode of endingNodes) { const endingNodeData = endingNode.data if (!endingNodeData) return res.status(500).send(`Ending node ${endingNode.id} data not found`) @@ -488,7 +490,8 @@ export class App { isStreaming = isEndingNode ? false : isFlowValidForStream(nodes, endingNodeData) } - const obj = { isStreaming } + // Once custom function ending node exists, flow is always unavailable to stream + const obj = { isStreaming: isEndingNodeExists ? false : isStreaming } return res.json(obj) }) @@ -1677,6 +1680,9 @@ export class App { if (!endingNodeIds.length) return res.status(500).send(`Ending nodes not found`) const endingNodes = nodes.filter((nd) => endingNodeIds.includes(nd.id)) + + let isEndingNodeExists = endingNodes.find((node) => node.data?.outputs?.output === 'EndingNode') + for (const endingNode of endingNodes) { const endingNodeData = endingNode.data if (!endingNodeData) return res.status(500).send(`Ending node ${endingNode.id} data not found`) @@ -1704,6 +1710,9 @@ export class App { isStreamValid = isFlowValidForStream(nodes, endingNodeData) } + // Once custom function ending node exists, flow is always unavailable to stream + isStreamValid = isEndingNodeExists ? false : isStreamValid + let chatHistory: IMessage[] = incomingInput.history ?? [] // When {{chat_history}} is used in Prompt Template, fetch the chat conversations from memory node From 2b67346ce0e124428452b78e7fe24ddc5e89b341 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 30 Jan 2024 17:42:48 +0000 Subject: [PATCH 39/40] add fix for not recognizing overrideConfig JSON value --- packages/server/src/utils/index.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index aa3e9ef64..2d3f000ac 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -611,28 +611,35 @@ export const resolveVariables = ( export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: ICommonObject) => { const types = 'inputs' - const getParamValues = (paramsObj: ICommonObject) => { + const getParamValues = (inputsObj: ICommonObject) => { for (const config in overrideConfig) { // If overrideConfig[key] is object if (overrideConfig[config] && typeof overrideConfig[config] === 'object') { const nodeIds = Object.keys(overrideConfig[config]) if (nodeIds.includes(flowNodeData.id)) { - paramsObj[config] = overrideConfig[config][flowNodeData.id] + inputsObj[config] = overrideConfig[config][flowNodeData.id] + continue + } else if (nodeIds.some((nodeId) => nodeId.includes(flowNodeData.name))) { + /* + * "systemMessagePrompt": { + * "chatPromptTemplate_0": "You are an assistant" <---- continue for loop if current node is chatPromptTemplate_1 + * } + */ continue } } - let paramValue = overrideConfig[config] ?? paramsObj[config] + let paramValue = overrideConfig[config] ?? inputsObj[config] // Check if boolean if (paramValue === 'true') paramValue = true else if (paramValue === 'false') paramValue = false - paramsObj[config] = paramValue + inputsObj[config] = paramValue } } - const paramsObj = flowNodeData[types] ?? {} + const inputsObj = flowNodeData[types] ?? {} - getParamValues(paramsObj) + getParamValues(inputsObj) return flowNodeData } From 214b312fe59207046f854c9d8909ba1fc03de166 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 30 Jan 2024 17:57:11 +0000 Subject: [PATCH 40/40] add input moderation to conversation chain --- .../ConversationChain/ConversationChain.ts | 27 +++++++++++++++++-- .../marketplaces/chatflows/Claude LLM.json | 12 ++++++++- .../chatflows/Simple Conversation Chain.json | 12 ++++++++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index 764f4f0e5..fd5a4fffc 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -7,6 +7,8 @@ import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from import { RunnableSequence } from 'langchain/schema/runnable' import { StringOutputParser } from 'langchain/schema/output_parser' import { ConsoleCallbackHandler as LCConsoleCallbackHandler } from '@langchain/core/tracers/console' +import { checkInputs, Moderation, streamResponse } from '../../moderation/Moderation' +import { formatResponse } from '../../outputparsers/OutputParserHelpers' let systemMessage = `The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.` const inputKey = 'input' @@ -26,7 +28,7 @@ class ConversationChain_Chains implements INode { constructor(fields?: { sessionId?: string }) { this.label = 'Conversation Chain' this.name = 'conversationChain' - this.version = 2.0 + this.version = 3.0 this.type = 'ConversationChain' this.icon = 'conv.svg' this.category = 'Chains' @@ -60,6 +62,14 @@ class ConversationChain_Chains implements INode { optional: true, list: 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 + }, { label: 'System Message', name: 'systemMessagePrompt', @@ -80,8 +90,21 @@ class ConversationChain_Chains implements INode { return chain } - async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { + async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { const memory = nodeData.inputs?.memory + const moderations = nodeData.inputs?.inputModeration as Moderation[] + + if (moderations && moderations.length > 0) { + try { + // Use the output of the moderation chain as input for the LLM chain + input = await checkInputs(moderations, input) + } catch (e) { + await new Promise((resolve) => setTimeout(resolve, 500)) + streamResponse(options.socketIO && options.socketIOClientId, e.message, options.socketIO, options.socketIOClientId) + return formatResponse(e.message) + } + } + const chain = prepareChain(nodeData, this.sessionId, options.chatHistory) const loggerHandler = new ConsoleCallbackHandler(options.logger) diff --git a/packages/server/marketplaces/chatflows/Claude LLM.json b/packages/server/marketplaces/chatflows/Claude LLM.json index 5d632ff11..7b32de48a 100644 --- a/packages/server/marketplaces/chatflows/Claude LLM.json +++ b/packages/server/marketplaces/chatflows/Claude LLM.json @@ -70,7 +70,7 @@ "data": { "id": "conversationChain_0", "label": "Conversation Chain", - "version": 2, + "version": 3, "name": "conversationChain", "type": "ConversationChain", "baseClasses": ["ConversationChain", "LLMChain", "BaseChain", "Runnable"], @@ -110,9 +110,19 @@ "description": "Override existing prompt with Chat Prompt Template. Human Message must includes {input} variable", "optional": true, "id": "conversationChain_0-input-chatPromptTemplate-ChatPromptTemplate" + }, + { + "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": "conversationChain_0-input-inputModeration-Moderation" } ], "inputs": { + "inputModeration": "", "model": "{{chatAnthropic_0.data.instance}}", "memory": "{{bufferMemory_0.data.instance}}", "chatPromptTemplate": "{{chatPromptTemplate_0.data.instance}}", diff --git a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json index b17e8a659..1ffbee447 100644 --- a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json +++ b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json @@ -269,7 +269,7 @@ "data": { "id": "conversationChain_0", "label": "Conversation Chain", - "version": 2, + "version": 3, "name": "conversationChain", "type": "ConversationChain", "baseClasses": ["ConversationChain", "LLMChain", "BaseChain", "Runnable"], @@ -309,9 +309,19 @@ "description": "Override existing prompt with Chat Prompt Template. Human Message must includes {input} variable", "optional": true, "id": "conversationChain_0-input-chatPromptTemplate-ChatPromptTemplate" + }, + { + "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": "conversationChain_0-input-inputModeration-Moderation" } ], "inputs": { + "inputModeration": "", "model": "{{chatOpenAI_0.data.instance}}", "memory": "{{bufferMemory_0.data.instance}}", "chatPromptTemplate": "",