Merge branch 'FlowiseAI:main' into UI/Custom-Icons

This commit is contained in:
Abhishek Shankar
2023-12-18 01:51:26 -05:00
committed by GitHub
42 changed files with 2382 additions and 733 deletions
+5 -1
View File
@@ -56,12 +56,16 @@ class RedisCache implements INode {
const password = getCredentialParam('redisCachePwd', credentialData, nodeData)
const portStr = getCredentialParam('redisCachePort', credentialData, nodeData)
const host = getCredentialParam('redisCacheHost', credentialData, nodeData)
const sslEnabled = getCredentialParam('redisCacheSslEnabled', credentialData, nodeData)
const tlsOptions = sslEnabled === true ? { tls: { rejectUnauthorized: false } } : {}
client = new Redis({
port: portStr ? parseInt(portStr) : 6379,
host,
username,
password
password,
...tlsOptions
})
} else {
client = new Redis(redisUrl)
@@ -71,12 +71,16 @@ class RedisEmbeddingsCache implements INode {
const password = getCredentialParam('redisCachePwd', credentialData, nodeData)
const portStr = getCredentialParam('redisCachePort', credentialData, nodeData)
const host = getCredentialParam('redisCacheHost', credentialData, nodeData)
const sslEnabled = getCredentialParam('redisCacheSslEnabled', credentialData, nodeData)
const tlsOptions = sslEnabled === true ? { tls: { rejectUnauthorized: false } } : {}
client = new Redis({
port: portStr ? parseInt(portStr) : 6379,
host,
username,
password
password,
...tlsOptions
})
} else {
client = new Redis(redisUrl)
@@ -1,9 +1,9 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { ChatBedrock } from 'langchain/chat_models/bedrock'
import { BedrockChat } from 'langchain/chat_models/bedrock'
import { BaseBedrockInput } from 'langchain/dist/util/bedrock'
import { BaseCache } from 'langchain/schema'
import { BaseLLMParams } from 'langchain/llms/base'
import { BaseChatModelParams } from 'langchain/chat_models/base'
/**
* I had to run the following to build the component
@@ -25,14 +25,14 @@ class AWSChatBedrock_ChatModels implements INode {
inputs: INodeParams[]
constructor() {
this.label = 'AWS Bedrock'
this.label = 'AWS ChatBedrock'
this.name = 'awsChatBedrock'
this.version = 3.0
this.type = 'AWSChatBedrock'
this.icon = 'awsBedrock.png'
this.category = 'Chat Models'
this.description = 'Wrapper around AWS Bedrock large language models that use the Chat endpoint'
this.baseClasses = [this.type, ...getBaseClasses(ChatBedrock)]
this.baseClasses = [this.type, ...getBaseClasses(BedrockChat)]
this.credential = {
label: 'AWS Credential',
name: 'credential',
@@ -102,6 +102,13 @@ class AWSChatBedrock_ChatModels implements INode {
],
default: 'anthropic.claude-v2'
},
{
label: 'Custom Model Name',
name: 'customModel',
description: 'If provided, will override model selected from Model Name option',
type: 'string',
optional: true
},
{
label: 'Temperature',
name: 'temperature',
@@ -109,6 +116,7 @@ class AWSChatBedrock_ChatModels implements INode {
step: 0.1,
description: 'Temperature parameter may not apply to certain model. Please check available model parameters',
optional: true,
additionalParams: true,
default: 0.7
},
{
@@ -118,6 +126,7 @@ class AWSChatBedrock_ChatModels implements INode {
step: 10,
description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters',
optional: true,
additionalParams: true,
default: 200
}
]
@@ -126,14 +135,15 @@ class AWSChatBedrock_ChatModels implements INode {
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const iRegion = nodeData.inputs?.region as string
const iModel = nodeData.inputs?.model as string
const customModel = nodeData.inputs?.customModel as string
const iTemperature = nodeData.inputs?.temperature as string
const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string
const cache = nodeData.inputs?.cache as BaseCache
const streaming = nodeData.inputs?.streaming as boolean
const obj: BaseBedrockInput & BaseLLMParams = {
const obj: BaseBedrockInput & BaseChatModelParams = {
region: iRegion,
model: iModel,
model: customModel ?? iModel,
maxTokens: parseInt(iMax_tokens_to_sample, 10),
temperature: parseFloat(iTemperature),
streaming: streaming ?? true
@@ -160,7 +170,7 @@ class AWSChatBedrock_ChatModels implements INode {
}
if (cache) obj.cache = cache
const amazonBedrock = new ChatBedrock(obj)
const amazonBedrock = new BedrockChat(obj)
return amazonBedrock
}
}
@@ -0,0 +1,107 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { BaseCache } from 'langchain/schema'
import { ChatGoogleGenerativeAI } from '@langchain/google-genai'
class GoogleGenerativeAI_ChatModels implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'ChatGoogleGenerativeAI'
this.name = 'chatGoogleGenerativeAI'
this.version = 1.0
this.type = 'ChatGoogleGenerativeAI'
this.icon = 'gemini.png'
this.category = 'Chat Models'
this.description = 'Wrapper around Google Gemini large language models that use the Chat endpoint'
this.baseClasses = [this.type, ...getBaseClasses(ChatGoogleGenerativeAI)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['googleGenerativeAI'],
optional: false,
description: 'Google Generative AI credential.'
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
type: 'options',
options: [
{
label: 'gemini-pro',
name: 'gemini-pro'
}
],
default: 'gemini-pro'
},
{
label: 'Temperature',
name: 'temperature',
type: 'number',
step: 0.1,
default: 0.9,
optional: true
},
{
label: 'Max Output Tokens',
name: 'maxOutputTokens',
type: 'number',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Top Probability',
name: 'topP',
type: 'number',
step: 0.1,
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const apiKey = getCredentialParam('googleGenerativeAPIKey', credentialData, nodeData)
const temperature = nodeData.inputs?.temperature as string
const modelName = nodeData.inputs?.modelName as string
const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string
const topP = nodeData.inputs?.topP as string
const cache = nodeData.inputs?.cache as BaseCache
const obj = {
apiKey: apiKey,
modelName: modelName,
maxOutputTokens: 2048
}
if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10)
const model = new ChatGoogleGenerativeAI(obj)
if (topP) model.topP = parseFloat(topP)
if (cache) model.cache = cache
if (temperature) model.temperature = parseFloat(temperature)
return model
}
}
module.exports = { nodeClass: GoogleGenerativeAI_ChatModels }
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@@ -0,0 +1,150 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { BaseCache } from 'langchain/schema'
import { ChatMistralAI, ChatMistralAIInput } from '@langchain/mistralai'
class ChatMistral_ChatModels implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]
constructor() {
this.label = 'ChatMistralAI'
this.name = 'chatMistralAI'
this.version = 1.0
this.type = 'ChatMistralAI'
this.icon = 'mistralai.png'
this.category = 'Chat Models'
this.description = 'Wrapper around Mistral large language models that use the Chat endpoint'
this.baseClasses = [this.type, ...getBaseClasses(ChatMistralAI)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['mistralAIApi']
}
this.inputs = [
{
label: 'Cache',
name: 'cache',
type: 'BaseCache',
optional: true
},
{
label: 'Model Name',
name: 'modelName',
type: 'options',
options: [
{
label: 'mistral-tiny',
name: 'mistral-tiny'
},
{
label: 'mistral-small',
name: 'mistral-small'
},
{
label: 'mistral-medium',
name: 'mistral-medium'
}
],
default: 'mistral-tiny'
},
{
label: 'Temperature',
name: 'temperature',
type: 'number',
description:
'What sampling temperature to use, between 0.0 and 1.0. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.',
step: 0.1,
default: 0.9,
optional: true
},
{
label: 'Max Output Tokens',
name: 'maxOutputTokens',
type: 'number',
description: 'The maximum number of tokens to generate in the completion.',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Top Probability',
name: 'topP',
type: 'number',
description:
'Nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.',
step: 0.1,
optional: true,
additionalParams: true
},
{
label: 'Random Seed',
name: 'randomSeed',
type: 'number',
description: 'The seed to use for random sampling. If set, different calls will generate deterministic results.',
step: 1,
optional: true,
additionalParams: true
},
{
label: 'Safe Mode',
name: 'safeMode',
type: 'boolean',
description: 'Whether to inject a safety prompt before all conversations.',
optional: true,
additionalParams: true
},
{
label: 'Override Endpoint',
name: 'overrideEndpoint',
type: 'string',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const apiKey = getCredentialParam('mistralAIAPIKey', credentialData, nodeData)
const temperature = nodeData.inputs?.temperature as string
const modelName = nodeData.inputs?.modelName as string
const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string
const topP = nodeData.inputs?.topP as string
const safeMode = nodeData.inputs?.safeMode as boolean
const randomSeed = nodeData.inputs?.safeMode as string
const overrideEndpoint = nodeData.inputs?.overrideEndpoint as string
// Waiting fix from langchain + mistral to enable streaming - https://github.com/mistralai/client-js/issues/18
const cache = nodeData.inputs?.cache as BaseCache
const obj: ChatMistralAIInput = {
apiKey: apiKey,
modelName: modelName
}
if (maxOutputTokens) obj.maxTokens = parseInt(maxOutputTokens, 10)
if (topP) obj.topP = parseFloat(topP)
if (cache) obj.cache = cache
if (temperature) obj.temperature = parseFloat(temperature)
if (randomSeed) obj.randomSeed = parseFloat(randomSeed)
if (safeMode) obj.safeMode = safeMode
if (overrideEndpoint) obj.endpoint = overrideEndpoint
const model = new ChatMistralAI(obj)
return model
}
}
module.exports = { nodeClass: ChatMistral_ChatModels }
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -18,7 +18,7 @@ class AWSBedrockEmbedding_Embeddings implements INode {
constructor() {
this.label = 'AWS Bedrock Embeddings'
this.name = 'AWSBedrockEmbeddings'
this.version = 2.0
this.version = 3.0
this.type = 'AWSBedrockEmbeddings'
this.icon = 'awsBedrock.png'
this.category = 'Embeddings'
@@ -86,6 +86,13 @@ class AWSBedrockEmbedding_Embeddings implements INode {
{ label: 'cohere.embed-multilingual-v3', name: 'cohere.embed-multilingual-v3' }
],
default: 'amazon.titan-embed-text-v1'
},
{
label: 'Custom Model Name',
name: 'customModel',
description: 'If provided, will override model selected from Model Name option',
type: 'string',
optional: true
}
]
}
@@ -93,9 +100,10 @@ class AWSBedrockEmbedding_Embeddings implements INode {
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const iRegion = nodeData.inputs?.region as string
const iModel = nodeData.inputs?.model as string
const customModel = nodeData.inputs?.customModel as string
const obj: BedrockEmbeddingsParams = {
model: iModel,
model: customModel ?? iModel,
region: iRegion
}
@@ -0,0 +1,104 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { GoogleGenerativeAIEmbeddings, GoogleGenerativeAIEmbeddingsParams } from '@langchain/google-genai'
import { TaskType } from '@google/generative-ai'
class GoogleGenerativeAIEmbedding_Embeddings implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'GoogleGenerativeAI Embeddings'
this.name = 'googleGenerativeAiEmbeddings'
this.version = 1.0
this.type = 'GoogleGenerativeAiEmbeddings'
this.icon = 'gemini.png'
this.category = 'Embeddings'
this.description = 'Google Generative API to generate embeddings for a given text'
this.baseClasses = [this.type, ...getBaseClasses(GoogleGenerativeAIEmbeddings)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['googleGenerativeAI'],
optional: false,
description: 'Google Generative AI credential.'
}
this.inputs = [
{
label: 'Model Name',
name: 'modelName',
type: 'options',
options: [
{
label: 'embedding-001',
name: 'embedding-001'
}
],
default: 'embedding-001'
},
{
label: 'Task Type',
name: 'tasktype',
type: 'options',
description: 'Type of task for which the embedding will be used',
options: [
{ label: 'TASK_TYPE_UNSPECIFIED', name: 'TASK_TYPE_UNSPECIFIED' },
{ label: 'RETRIEVAL_QUERY', name: 'RETRIEVAL_QUERY' },
{ label: 'RETRIEVAL_DOCUMENT', name: 'RETRIEVAL_DOCUMENT' },
{ label: 'SEMANTIC_SIMILARITY', name: 'SEMANTIC_SIMILARITY' },
{ label: 'CLASSIFICATION', name: 'CLASSIFICATION' },
{ label: 'CLUSTERING', name: 'CLUSTERING' }
],
default: 'TASK_TYPE_UNSPECIFIED'
}
]
}
// eslint-disable-next-line unused-imports/no-unused-vars
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const modelName = nodeData.inputs?.modelName as string
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const apiKey = getCredentialParam('googleGenerativeAPIKey', credentialData, nodeData)
let taskType: TaskType
switch (nodeData.inputs?.tasktype as string) {
case 'RETRIEVAL_QUERY':
taskType = TaskType.RETRIEVAL_QUERY
break
case 'RETRIEVAL_DOCUMENT':
taskType = TaskType.RETRIEVAL_DOCUMENT
break
case 'SEMANTIC_SIMILARITY':
taskType = TaskType.SEMANTIC_SIMILARITY
break
case 'CLASSIFICATION':
taskType = TaskType.CLASSIFICATION
break
case 'CLUSTERING':
taskType = TaskType.CLUSTERING
break
default:
taskType = TaskType.TASK_TYPE_UNSPECIFIED
break
}
const obj: GoogleGenerativeAIEmbeddingsParams = {
apiKey: apiKey,
modelName: modelName,
taskType: taskType
}
const model = new GoogleGenerativeAIEmbeddings(obj)
return model
}
}
module.exports = { nodeClass: GoogleGenerativeAIEmbedding_Embeddings }
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@@ -0,0 +1,95 @@
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
import { MistralAIEmbeddings, MistralAIEmbeddingsParams } from '@langchain/mistralai'
class MistralEmbedding_Embeddings implements INode {
label: string
name: string
version: number
type: string
icon: string
category: string
description: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'MistralAI Embeddings'
this.name = 'mistralAI Embeddings'
this.version = 1.0
this.type = 'MistralAIEmbeddings'
this.icon = 'mistralai.png'
this.category = 'Embeddings'
this.description = 'MistralAI API to generate embeddings for a given text'
this.baseClasses = [this.type, ...getBaseClasses(MistralAIEmbeddings)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['mistralAIApi']
}
this.inputs = [
{
label: 'Model Name',
name: 'modelName',
type: 'options',
options: [
{
label: 'mistral-embed',
name: 'mistral-embed'
}
],
default: 'mistral-embed'
},
{
label: 'Batch Size',
name: 'batchSize',
type: 'number',
step: 1,
default: 512,
optional: true,
additionalParams: true
},
{
label: 'Strip New Lines',
name: 'stripNewLines',
type: 'boolean',
default: true,
optional: true,
additionalParams: true
},
{
label: 'Override Endpoint',
name: 'overrideEndpoint',
type: 'string',
optional: true,
additionalParams: true
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const modelName = nodeData.inputs?.modelName as string
const batchSize = nodeData.inputs?.batchSize as string
const stripNewLines = nodeData.inputs?.stripNewLines as boolean
const overrideEndpoint = nodeData.inputs?.overrideEndpoint as string
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const apiKey = getCredentialParam('mistralAIAPIKey', credentialData, nodeData)
const obj: MistralAIEmbeddingsParams = {
apiKey: apiKey,
modelName: modelName
}
if (batchSize) obj.batchSize = parseInt(batchSize, 10)
if (stripNewLines) obj.stripNewLines = stripNewLines
if (overrideEndpoint) obj.endpoint = overrideEndpoint
const model = new MistralAIEmbeddings(obj)
return model
}
}
module.exports = { nodeClass: MistralEmbedding_Embeddings }
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -27,7 +27,7 @@ class AWSBedrock_LLMs implements INode {
constructor() {
this.label = 'AWS Bedrock'
this.name = 'awsBedrock'
this.version = 2.0
this.version = 3.0
this.type = 'AWSBedrock'
this.icon = 'awsBedrock.png'
this.category = 'LLMs'
@@ -105,6 +105,13 @@ class AWSBedrock_LLMs implements INode {
{ label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' }
]
},
{
label: 'Custom Model Name',
name: 'customModel',
description: 'If provided, will override model selected from Model Name option',
type: 'string',
optional: true
},
{
label: 'Temperature',
name: 'temperature',
@@ -112,6 +119,7 @@ class AWSBedrock_LLMs implements INode {
step: 0.1,
description: 'Temperature parameter may not apply to certain model. Please check available model parameters',
optional: true,
additionalParams: true,
default: 0.7
},
{
@@ -121,6 +129,7 @@ class AWSBedrock_LLMs implements INode {
step: 10,
description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters',
optional: true,
additionalParams: true,
default: 200
}
]
@@ -129,11 +138,12 @@ class AWSBedrock_LLMs implements INode {
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const iRegion = nodeData.inputs?.region as string
const iModel = nodeData.inputs?.model as string
const customModel = nodeData.inputs?.customModel as string
const iTemperature = nodeData.inputs?.temperature as string
const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string
const cache = nodeData.inputs?.cache as BaseCache
const obj: Partial<BaseBedrockInput> & BaseLLMParams = {
model: iModel,
model: customModel ?? iModel,
region: iRegion,
temperature: parseFloat(iTemperature),
maxTokens: parseInt(iMax_tokens_to_sample, 10)
@@ -57,6 +57,14 @@ class RedisBackedChatMemory_Memory implements INode {
type: 'string',
default: 'chat_history',
additionalParams: true
},
{
label: 'Window Size',
name: 'windowSize',
type: 'number',
description: 'Window of size k to surface the last k back-and-forth to use as memory.',
additionalParams: true,
optional: true
}
]
}
@@ -89,6 +97,7 @@ const initalizeRedis = async (nodeData: INodeData, options: ICommonObject): Prom
const sessionId = nodeData.inputs?.sessionId as string
const sessionTTL = nodeData.inputs?.sessionTTL as number
const memoryKey = nodeData.inputs?.memoryKey as string
const windowSize = nodeData.inputs?.windowSize as number
const chatId = options?.chatId as string
let isSessionIdUsingChatMessageId = false
@@ -103,12 +112,16 @@ const initalizeRedis = async (nodeData: INodeData, options: ICommonObject): Prom
const password = getCredentialParam('redisCachePwd', credentialData, nodeData)
const portStr = getCredentialParam('redisCachePort', credentialData, nodeData)
const host = getCredentialParam('redisCacheHost', credentialData, nodeData)
const sslEnabled = getCredentialParam('redisCacheSslEnabled', credentialData, nodeData)
const tlsOptions = sslEnabled === true ? { tls: { rejectUnauthorized: false } } : {}
client = new Redis({
port: portStr ? parseInt(portStr) : 6379,
host,
username,
password
password,
...tlsOptions
})
} else {
client = new Redis(redisUrl)
@@ -129,7 +142,7 @@ const initalizeRedis = async (nodeData: INodeData, options: ICommonObject): Prom
const redisChatMessageHistory = new RedisChatMessageHistory(obj)
redisChatMessageHistory.getMessages = async (): Promise<BaseMessage[]> => {
const rawStoredMessages = await client.lrange((redisChatMessageHistory as any).sessionId, 0, -1)
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)
}
@@ -2,37 +2,7 @@ import { z } from 'zod'
import { CallbackManagerForToolRun } from 'langchain/callbacks'
import { StructuredTool, ToolParams } from 'langchain/tools'
import { NodeVM } from 'vm2'
/*
* List of dependencies allowed to be import in vm2
*/
const availableDependencies = [
'@dqbd/tiktoken',
'@getzep/zep-js',
'@huggingface/inference',
'@pinecone-database/pinecone',
'@supabase/supabase-js',
'axios',
'cheerio',
'chromadb',
'cohere-ai',
'd3-dsv',
'form-data',
'graphql',
'html-to-text',
'langchain',
'linkifyjs',
'mammoth',
'moment',
'node-fetch',
'pdf-parse',
'pdfjs-dist',
'playwright',
'puppeteer',
'srt-parser-2',
'typeorm',
'weaviate-ts-client'
]
import { availableDependencies } from '../../../src/utils'
export interface BaseDynamicToolInput extends ToolParams {
name: string
@@ -0,0 +1,124 @@
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { NodeVM } from 'vm2'
import { availableDependencies, handleEscapeCharacters } from '../../../src/utils'
class CustomFunction_Utilities implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
outputs: INodeOutputsValue[]
constructor() {
this.label = 'Custom JS Function'
this.name = 'customFunction'
this.version = 1.0
this.type = 'CustomFunction'
this.icon = 'customfunction.svg'
this.category = 'Utilities'
this.description = `Execute custom javascript function`
this.baseClasses = [this.type, 'Utilities']
this.inputs = [
{
label: 'Input Variables',
name: 'functionInputVariables',
description: 'Input variables can be used in the function with prefix $. For example: $var',
type: 'json',
optional: true,
acceptVariable: true,
list: true
},
{
label: 'Function Name',
name: 'functionName',
type: 'string',
optional: true,
placeholder: 'My Function'
},
{
label: 'Javascript Function',
name: 'javascriptFunction',
type: 'code'
}
]
this.outputs = [
{
label: 'Output',
name: 'output',
baseClasses: ['string', 'number', 'boolean', 'json', 'array']
}
]
}
async init(nodeData: INodeData, input: string): Promise<any> {
const javascriptFunction = nodeData.inputs?.javascriptFunction as string
const functionInputVariablesRaw = nodeData.inputs?.functionInputVariables
let inputVars: ICommonObject = {}
if (functionInputVariablesRaw) {
try {
inputVars =
typeof functionInputVariablesRaw === 'object' ? functionInputVariablesRaw : JSON.parse(functionInputVariablesRaw)
} catch (exception) {
throw new Error("Invalid JSON in the PromptTemplate's promptValues: " + exception)
}
}
let sandbox: any = { $input: input }
if (Object.keys(inputVars).length) {
for (const item in inputVars) {
sandbox[`$${item}`] = inputVars[item]
}
}
const defaultAllowBuiltInDep = [
'assert',
'buffer',
'crypto',
'events',
'http',
'https',
'net',
'path',
'querystring',
'timers',
'tls',
'url',
'zlib'
]
const builtinDeps = process.env.TOOL_FUNCTION_BUILTIN_DEP
? defaultAllowBuiltInDep.concat(process.env.TOOL_FUNCTION_BUILTIN_DEP.split(','))
: defaultAllowBuiltInDep
const externalDeps = process.env.TOOL_FUNCTION_EXTERNAL_DEP ? process.env.TOOL_FUNCTION_EXTERNAL_DEP.split(',') : []
const deps = availableDependencies.concat(externalDeps)
const nodeVMOptions = {
console: 'inherit',
sandbox,
require: {
external: { modules: deps },
builtin: builtinDeps
}
} as any
const vm = new NodeVM(nodeVMOptions)
try {
const response = await vm.run(`module.exports = async function() {${javascriptFunction}}()`, __dirname)
if (typeof response === 'string') {
return handleEscapeCharacters(response, false)
}
return response
} catch (e) {
throw new Error(e)
}
}
}
module.exports = { nodeClass: CustomFunction_Utilities }
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-function" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 4m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h10.666a2.667 2.667 0 0 1 2.667 2.667v10.666a2.667 2.667 0 0 1 -2.667 2.667h-10.666a2.667 2.667 0 0 1 -2.667 -2.667z" /><path d="M9 15.5v.25c0 .69 .56 1.25 1.25 1.25c.71 0 1.304 -.538 1.374 -1.244l.752 -7.512a1.381 1.381 0 0 1 1.374 -1.244c.69 0 1.25 .56 1.25 1.25v.25" /><path d="M9 12h6" /></svg>

After

Width:  |  Height:  |  Size: 628 B

@@ -0,0 +1,52 @@
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
class GetVariable_Utilities implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
outputs: INodeOutputsValue[]
constructor() {
this.label = 'Get Variable'
this.name = 'getVariable'
this.version = 1.0
this.type = 'GetVariable'
this.icon = 'getvar.svg'
this.category = 'Utilities'
this.description = `Get variable that was saved using Set Variable node`
this.baseClasses = [this.type, 'Utilities']
this.inputs = [
{
label: 'Variable Name',
name: 'variableName',
type: 'string',
placeholder: 'var1'
}
]
this.outputs = [
{
label: 'Output',
name: 'output',
baseClasses: ['string', 'number', 'boolean', 'json', 'array']
}
]
}
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const variableName = nodeData.inputs?.variableName as string
const dynamicVars = options.dynamicVariables as Record<string, unknown>
if (Object.prototype.hasOwnProperty.call(dynamicVars, variableName)) {
return dynamicVars[variableName]
}
return undefined
}
}
module.exports = { nodeClass: GetVariable_Utilities }
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-book-download" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 20h-6a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12v5" /><path d="M13 16h-7a2 2 0 0 0 -2 2" /><path d="M15 19l3 3l3 -3" /><path d="M18 22v-9" /></svg>

After

Width:  |  Height:  |  Size: 438 B

@@ -0,0 +1,56 @@
import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
class SetVariable_Utilities implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs: INodeParams[]
outputs: INodeOutputsValue[]
constructor() {
this.label = 'Set Variable'
this.name = 'setVariable'
this.version = 1.0
this.type = 'SetVariable'
this.icon = 'setvar.svg'
this.category = 'Utilities'
this.description = `Set variable which can be retrieved at a later stage. Variable is only available during runtime.`
this.baseClasses = [this.type, 'Utilities']
this.inputs = [
{
label: 'Input',
name: 'input',
type: 'string | number | boolean | json | array',
optional: true,
list: true
},
{
label: 'Variable Name',
name: 'variableName',
type: 'string',
placeholder: 'var1'
}
]
this.outputs = [
{
label: 'Output',
name: 'output',
baseClasses: ['string', 'number', 'boolean', 'json', 'array']
}
]
}
async init(nodeData: INodeData): Promise<any> {
const inputRaw = nodeData.inputs?.input
const variableName = nodeData.inputs?.variableName as string
return { output: inputRaw, dynamicVariables: { [variableName]: inputRaw } }
}
}
module.exports = { nodeClass: SetVariable_Utilities }
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-book-upload" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 20h-8a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12v5" /><path d="M11 16h-5a2 2 0 0 0 -2 2" /><path d="M15 16l3 -3l3 3" /><path d="M18 13v9" /></svg>

After

Width:  |  Height:  |  Size: 435 B

@@ -183,13 +183,26 @@ const prepareConnectionOptions = (
} else if (cloudId) {
let username = getCredentialParam('username', credentialData, nodeData)
let password = getCredentialParam('password', credentialData, nodeData)
elasticSearchClientOptions = {
cloud: {
id: cloudId
},
auth: {
username: username,
password: password
if (cloudId.startsWith('http')) {
elasticSearchClientOptions = {
node: cloudId,
auth: {
username: username,
password: password
},
tls: {
rejectUnauthorized: false
}
}
} else {
elasticSearchClientOptions = {
cloud: {
id: cloudId
},
auth: {
username: username,
password: password
}
}
}
}