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 a2c1eef3..dfa05983 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 dfa05983..d7ae2667 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 f50e3d95..a8ac8830 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 d7ae2667..04d7d735 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 9b7b724a..33f6b76e 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 04d7d735..0f212a0a 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 33f6b76e..a459a8ec 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 ed54ac66..8b5dbe8f 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 6d4c1887..14685aee 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 5d8b81e9..a9ad9278 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 88d1aaac..747c0f39 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 0fe69dd1..318ce864 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 c8c88bf3..24cbb22e 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 8b5dbe8f..5f1b1848 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 08cd8298..013cab2d 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 14685aee..adc3b0c6 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 a9ad9278..d4acef49 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 d4acef49..96bbab57 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 88d1aaac..e51c79c6 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 0fe69dd1..c703ae4b 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 c8c88bf3..99b7c5a8 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 ed54ac66..58812cab 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 762315ac..4cd9225f 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 08cd8298..09ce2aa4 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 5f321900..2cb701c1 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 b3d0045b..7deec67e 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 002c08c1..87f6d6d2 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 eabc8f2e..af99be9d 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 85cd5e4c..ef997feb 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 0062cd43..30ea96ae 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 81e3f230..d0c74fcb 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 61d97c4d..e16377d2 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 0a5d4ac6..f8d8d26c 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 b8e2cf01..12bea993 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 b27d3886..031a29c0 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 4378a47d..3b9a8c21 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 253a1dfc..1dfe1e33 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 16f70801..6975fc68 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 5e33b63a..93009574 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 690d3ce5..f3fddebf 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 98d12238..7dafcedf 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 1f6cc624..ed823a21 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 33841d15..eaf56dff 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 cf0fa4d4..1b3e48e1 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 f7b2fbfb..f96e07c2 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 0a888a6b..314e24a6 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 e86b28c9..f685e43b 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 d53cb55e..e5a16caa 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 17e59236..e3e80dcc 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 0ddec74f..46e1257d 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 3181bc47..267d8222 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 b776dd37..e4a7fab8 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 bee565ce..832e85c7 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 026a03d8..92e42178 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 ad08fed8..406c2e52 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 9689bf8c..b17e8a65 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 b07124c0..f2e3a4a2 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 77a8bbfd..92336443 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 f1fa0764..0bf49252 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 d905b54b..2376e29e 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 df05feef..4013985e 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 30ea96ae..4edbf823 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 d0c74fcb..3137d511 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 3b9a8c21..810c2b35 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 1dfe1e33..e73a9d28 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 f96e07c2..ef928854 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 f685e43b..8c9e8537 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 4013985e..a5a53233 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 c593c20d..b35de5ae 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 b35de5ae..c2c7ada6 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 c2c7ada6..3c2903f3 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 3c2903f3..7399ad81 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 7399ad81..b7309dcd 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 4e61c239..c93adf58 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 fe1b4df8..b74413fe 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 baf4ea6b..c54e07b5 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 1d5f7788..80899942 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 49f9e8ff..0dddf782 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 b6aa6ebb..e87b49f9 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 e8848d33..6f2ec9b3 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 4da58eaf..c4394824 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 762315ac..9ea391ef 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 9ea391ef..a23b4ce2 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 0f212a0a..78ad7a66 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 78ad7a66..6fdb070a 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 6fdb070a..de913b90 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 de913b90..4558edb5 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 4558edb5..ed157264 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 ed157264..d0ed3b44 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 d0ed3b44..7d5e8ad0 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 7d5e8ad0..76d6e349 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 76d6e349..011975a7 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 011975a7..90a7ba03 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 90a7ba03..8845bbe0 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 8845bbe0..b0478100 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 b0478100..14815297 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 a459a8ec..9b7b724a 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 b70caa4c..75897e6c 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 c93adf58..cf7b43c9 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 c21c887a..9c25b2a9 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 d420a88d..1e44acdb 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 cc74a015..4e4a4af8 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 5e241d50..ab08097b 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 810c2b35..40c689f5 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 b0bb06f5..045e40dd 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 aa3e9ef6..2d3f000a 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 764f4f0e..fd5a4fff 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 5d632ff1..7b32de48 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 b17e8a65..1ffbee44 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": "",