Merge branch 'FlowiseAI:main' into UI/Custom-Icons
|
|
@ -0,0 +1,26 @@
|
|||
import { INodeParams, INodeCredential } from '../src/Interface'
|
||||
|
||||
class GoogleGenerativeAICredential implements INodeCredential {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'Google Generative AI'
|
||||
this.name = 'googleGenerativeAI'
|
||||
this.version = 1.0
|
||||
this.description =
|
||||
'You can get your API key from official <a target="_blank" href="https://ai.google.dev/tutorials/setup">page</a> here.'
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Google AI API Key',
|
||||
name: 'googleGenerativeAPIKey',
|
||||
type: 'password'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { credClass: GoogleGenerativeAICredential }
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { INodeParams, INodeCredential } from '../src/Interface'
|
||||
|
||||
class MistralAICredential implements INodeCredential {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'MistralAI API'
|
||||
this.name = 'mistralAIApi'
|
||||
this.version = 1.0
|
||||
this.description = 'You can get your API key from official <a target="_blank" href="https://console.mistral.ai/">console</a> here.'
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'MistralAI API Key',
|
||||
name: 'mistralAIAPIKey',
|
||||
type: 'password'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { credClass: MistralAICredential }
|
||||
|
|
@ -35,6 +35,11 @@ class RedisCacheApi implements INodeCredential {
|
|||
name: 'redisCachePwd',
|
||||
type: 'password',
|
||||
placeholder: '<REDIS_PASSWORD>'
|
||||
},
|
||||
{
|
||||
label: 'Use SSL',
|
||||
name: 'redisCacheSslEnabled',
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
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 }
|
||||
|
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 }
|
||||
|
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 }
|
||||
|
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
"@gomomento/sdk-core": "^1.51.1",
|
||||
"@google-ai/generativelanguage": "^0.2.1",
|
||||
"@huggingface/inference": "^2.6.1",
|
||||
"@langchain/google-genai": "^0.0.3",
|
||||
"@langchain/mistralai": "^0.0.3",
|
||||
"@notionhq/client": "^2.2.8",
|
||||
"@opensearch-project/opensearch": "^1.2.0",
|
||||
"@pinecone-database/pinecone": "^1.1.1",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,63 @@ import { AIMessage, HumanMessage } from 'langchain/schema'
|
|||
|
||||
export const numberOrExpressionRegex = '^(\\d+\\.?\\d*|{{.*}})$' //return true if string consists only numbers OR expression {{}}
|
||||
export const notEmptyRegex = '(.|\\s)*\\S(.|\\s)*' //return true if string is not empty or blank
|
||||
/*
|
||||
* List of dependencies allowed to be import in vm2
|
||||
*/
|
||||
export const availableDependencies = [
|
||||
'@aws-sdk/client-bedrock-runtime',
|
||||
'@aws-sdk/client-dynamodb',
|
||||
'@aws-sdk/client-s3',
|
||||
'@elastic/elasticsearch',
|
||||
'@dqbd/tiktoken',
|
||||
'@getzep/zep-js',
|
||||
'@gomomento/sdk',
|
||||
'@gomomento/sdk-core',
|
||||
'@google-ai/generativelanguage',
|
||||
'@huggingface/inference',
|
||||
'@notionhq/client',
|
||||
'@opensearch-project/opensearch',
|
||||
'@pinecone-database/pinecone',
|
||||
'@qdrant/js-client-rest',
|
||||
'@supabase/supabase-js',
|
||||
'@upstash/redis',
|
||||
'@zilliz/milvus2-sdk-node',
|
||||
'apify-client',
|
||||
'axios',
|
||||
'cheerio',
|
||||
'chromadb',
|
||||
'cohere-ai',
|
||||
'd3-dsv',
|
||||
'faiss-node',
|
||||
'form-data',
|
||||
'google-auth-library',
|
||||
'graphql',
|
||||
'html-to-text',
|
||||
'ioredis',
|
||||
'langchain',
|
||||
'langfuse',
|
||||
'langsmith',
|
||||
'linkifyjs',
|
||||
'llmonitor',
|
||||
'mammoth',
|
||||
'moment',
|
||||
'mongodb',
|
||||
'mysql2',
|
||||
'node-fetch',
|
||||
'node-html-markdown',
|
||||
'notion-to-md',
|
||||
'openai',
|
||||
'pdf-parse',
|
||||
'pdfjs-dist',
|
||||
'pg',
|
||||
'playwright',
|
||||
'puppeteer',
|
||||
'redis',
|
||||
'replicate',
|
||||
'srt-parser-2',
|
||||
'typeorm',
|
||||
'weaviate-ts-client'
|
||||
]
|
||||
|
||||
/**
|
||||
* Get base classes of components
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ import { Tool } from './database/entities/Tool'
|
|||
import { Assistant } from './database/entities/Assistant'
|
||||
import { ChatflowPool } from './ChatflowPool'
|
||||
import { CachePool } from './CachePool'
|
||||
import { ICommonObject, IMessage, INodeOptionsValue } from 'flowise-components'
|
||||
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'
|
||||
|
|
@ -281,6 +281,29 @@ export class App {
|
|||
}
|
||||
})
|
||||
|
||||
// execute custom function node
|
||||
this.app.post('/api/v1/node-custom-function', async (req: Request, res: Response) => {
|
||||
const body = req.body
|
||||
const nodeData = { inputs: body }
|
||||
if (Object.prototype.hasOwnProperty.call(this.nodesPool.componentNodes, 'customFunction')) {
|
||||
try {
|
||||
const nodeInstanceFilePath = this.nodesPool.componentNodes['customFunction'].filePath as string
|
||||
const nodeModule = await import(nodeInstanceFilePath)
|
||||
const newNodeInstance = new nodeModule.nodeClass()
|
||||
|
||||
const returnData = await newNodeInstance.init(nodeData)
|
||||
const result = typeof returnData === 'string' ? handleEscapeCharacters(returnData, true) : returnData
|
||||
|
||||
return res.json(result)
|
||||
} catch (error) {
|
||||
return res.status(500).send(`Error running custom function: ${error}`)
|
||||
}
|
||||
} else {
|
||||
res.status(404).send(`Node customFunction not found`)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
// ----------------------------------------
|
||||
// Chatflows
|
||||
// ----------------------------------------
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ export const buildLangchain = async (
|
|||
// Create a Queue and add our initial node in it
|
||||
const nodeQueue = [] as INodeQueue[]
|
||||
const exploredNode = {} as IExploredNode
|
||||
const dynamicVariables = {} as Record<string, unknown>
|
||||
|
||||
// In the case of infinite loop, only max 3 loops will be executed
|
||||
const maxLoop = 3
|
||||
|
|
@ -267,20 +268,36 @@ export const buildLangchain = async (
|
|||
appDataSource,
|
||||
databaseEntities,
|
||||
logger,
|
||||
cachePool
|
||||
cachePool,
|
||||
dynamicVariables
|
||||
})
|
||||
logger.debug(`[server]: Finished upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||
break
|
||||
} else {
|
||||
logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||
flowNodes[nodeIndex].data.instance = await newNodeInstance.init(reactFlowNodeData, question, {
|
||||
let outputResult = await newNodeInstance.init(reactFlowNodeData, question, {
|
||||
chatId,
|
||||
chatflowid,
|
||||
appDataSource,
|
||||
databaseEntities,
|
||||
logger,
|
||||
cachePool
|
||||
cachePool,
|
||||
dynamicVariables
|
||||
})
|
||||
|
||||
// Save dynamic variables
|
||||
if (reactFlowNode.data.name === 'setVariable') {
|
||||
const dynamicVars = outputResult?.dynamicVariables ?? {}
|
||||
|
||||
for (const variableKey in dynamicVars) {
|
||||
dynamicVariables[variableKey] = dynamicVars[variableKey]
|
||||
}
|
||||
|
||||
outputResult = outputResult?.output
|
||||
}
|
||||
|
||||
flowNodes[nodeIndex].data.instance = outputResult
|
||||
|
||||
logger.debug(`[server]: Finished initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||
}
|
||||
} catch (e: any) {
|
||||
|
|
@ -711,6 +728,7 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component
|
|||
|
||||
/**
|
||||
* Check to see if flow valid for stream
|
||||
* TODO: perform check from component level. i.e: set streaming on component, and check here
|
||||
* @param {IReactFlowNode[]} reactFlowNodes
|
||||
* @param {INodeData} endingNodeData
|
||||
* @returns {boolean}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,20 @@
|
|||
"email": "henryheng@flowiseai.com"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-javascript": "^6.2.1",
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/view": "^6.22.3",
|
||||
"@emotion/cache": "^11.4.0",
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/styled": "^11.10.6",
|
||||
"@mui/icons-material": "^5.0.3",
|
||||
"@mui/material": "^5.11.12",
|
||||
"@mui/lab": "^5.0.0-alpha.156",
|
||||
"@mui/material": "^5.15.0",
|
||||
"@mui/x-data-grid": "^6.8.0",
|
||||
"@tabler/icons": "^1.39.1",
|
||||
"@uiw/codemirror-theme-sublime": "^4.21.21",
|
||||
"@uiw/codemirror-theme-vscode": "^4.21.21",
|
||||
"@uiw/react-codemirror": "^4.21.21",
|
||||
"clsx": "^1.1.1",
|
||||
"flowise-embed": "*",
|
||||
"flowise-embed-react": "*",
|
||||
|
|
@ -26,7 +33,6 @@
|
|||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.3",
|
||||
"notistack": "^2.0.4",
|
||||
"prismjs": "^1.28.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^18.2.0",
|
||||
"react-code-blocks": "^0.0.9-0",
|
||||
|
|
@ -39,7 +45,6 @@
|
|||
"react-redux": "^8.0.5",
|
||||
"react-router": "~6.3.0",
|
||||
"react-router-dom": "~6.3.0",
|
||||
"react-simple-code-editor": "^0.11.2",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"reactflow": "^11.5.6",
|
||||
"redux": "^4.0.5",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ const getAllNodes = () => client.get('/nodes')
|
|||
|
||||
const getSpecificNode = (name) => client.get(`/nodes/${name}`)
|
||||
|
||||
const executeCustomFunctionNode = (body) => client.post(`/node-custom-function`, body)
|
||||
|
||||
export default {
|
||||
getAllNodes,
|
||||
getSpecificNode
|
||||
getSpecificNode,
|
||||
executeCustomFunctionNode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,24 @@ import { createPortal } from 'react-dom'
|
|||
import { useState, useEffect } from 'react'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar'
|
||||
|
||||
// MUI
|
||||
import { Button, Dialog, DialogActions, DialogContent, Typography } from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar'
|
||||
import { LoadingButton } from '@mui/lab'
|
||||
|
||||
// Project Import
|
||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||
import { DarkCodeEditor } from 'ui-component/editor/DarkCodeEditor'
|
||||
import { LightCodeEditor } from 'ui-component/editor/LightCodeEditor'
|
||||
import { CodeEditor } from 'ui-component/editor/CodeEditor'
|
||||
|
||||
// Store
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
|
||||
// API
|
||||
import nodesApi from 'api/nodes'
|
||||
import useApi from 'hooks/useApi'
|
||||
|
||||
import './ExpandTextDialog.css'
|
||||
|
||||
const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||
|
|
@ -18,18 +28,30 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
|||
const theme = useTheme()
|
||||
const dispatch = useDispatch()
|
||||
const customization = useSelector((state) => state.customization)
|
||||
const languageType = 'json'
|
||||
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
const [inputParam, setInputParam] = useState(null)
|
||||
const [languageType, setLanguageType] = useState('json')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [codeExecutedResult, setCodeExecutedResult] = useState('')
|
||||
|
||||
const executeCustomFunctionNodeApi = useApi(nodesApi.executeCustomFunctionNode)
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogProps.value) setInputValue(dialogProps.value)
|
||||
if (dialogProps.inputParam) setInputParam(dialogProps.inputParam)
|
||||
if (dialogProps.inputParam) {
|
||||
setInputParam(dialogProps.inputParam)
|
||||
if (dialogProps.inputParam.type === 'code') {
|
||||
setLanguageType('js')
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
setInputValue('')
|
||||
setLoading(false)
|
||||
setInputParam(null)
|
||||
setLanguageType('json')
|
||||
setCodeExecutedResult('')
|
||||
}
|
||||
}, [dialogProps])
|
||||
|
||||
|
|
@ -39,11 +61,31 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
|||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(executeCustomFunctionNodeApi.loading)
|
||||
}, [executeCustomFunctionNodeApi.loading])
|
||||
|
||||
useEffect(() => {
|
||||
if (executeCustomFunctionNodeApi.data) {
|
||||
setCodeExecutedResult(executeCustomFunctionNodeApi.data)
|
||||
}
|
||||
}, [executeCustomFunctionNodeApi.data])
|
||||
|
||||
useEffect(() => {
|
||||
if (executeCustomFunctionNodeApi.error) {
|
||||
if (typeof executeCustomFunctionNodeApi.error === 'object' && executeCustomFunctionNodeApi.error?.response?.data) {
|
||||
setCodeExecutedResult(executeCustomFunctionNodeApi.error?.response?.data)
|
||||
} else if (typeof executeCustomFunctionNodeApi.error === 'string') {
|
||||
setCodeExecutedResult(executeCustomFunctionNodeApi.error)
|
||||
}
|
||||
}
|
||||
}, [executeCustomFunctionNodeApi.error])
|
||||
|
||||
const component = show ? (
|
||||
<Dialog open={show} fullWidth maxWidth='md' aria-labelledby='alert-dialog-title' aria-describedby='alert-dialog-description'>
|
||||
<DialogContent>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
{inputParam && inputParam.type === 'string' && (
|
||||
{inputParam && (inputParam.type === 'string' || inputParam.type === 'code') && (
|
||||
<div style={{ flex: 70 }}>
|
||||
<Typography sx={{ mb: 2, ml: 1 }} variant='h4'>
|
||||
{inputParam.label}
|
||||
|
|
@ -54,42 +96,66 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
|||
borderColor: theme.palette.grey['500'],
|
||||
borderRadius: '12px',
|
||||
height: '100%',
|
||||
maxHeight: 'calc(100vh - 220px)',
|
||||
maxHeight: languageType === 'js' ? 'calc(100vh - 250px)' : 'calc(100vh - 220px)',
|
||||
overflowX: 'hidden',
|
||||
backgroundColor: 'white'
|
||||
}}
|
||||
>
|
||||
{customization.isDarkMode ? (
|
||||
<DarkCodeEditor
|
||||
disabled={dialogProps.disabled}
|
||||
value={inputValue}
|
||||
onValueChange={(code) => setInputValue(code)}
|
||||
placeholder={inputParam.placeholder}
|
||||
type={languageType}
|
||||
style={{
|
||||
fontSize: '0.875rem',
|
||||
minHeight: 'calc(100vh - 220px)',
|
||||
width: '100%'
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<LightCodeEditor
|
||||
disabled={dialogProps.disabled}
|
||||
value={inputValue}
|
||||
onValueChange={(code) => setInputValue(code)}
|
||||
placeholder={inputParam.placeholder}
|
||||
type={languageType}
|
||||
style={{
|
||||
fontSize: '0.875rem',
|
||||
minHeight: 'calc(100vh - 220px)',
|
||||
width: '100%'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<CodeEditor
|
||||
disabled={dialogProps.disabled}
|
||||
value={inputValue}
|
||||
height={languageType === 'js' ? 'calc(100vh - 250px)' : 'calc(100vh - 220px)'}
|
||||
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||
lang={languageType}
|
||||
placeholder={inputParam.placeholder}
|
||||
basicSetup={
|
||||
languageType === 'json'
|
||||
? { lineNumbers: false, foldGutter: false, autocompletion: false, highlightActiveLine: false }
|
||||
: {}
|
||||
}
|
||||
onValueChange={(code) => setInputValue(code)}
|
||||
/>
|
||||
</PerfectScrollbar>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{languageType === 'js' && (
|
||||
<LoadingButton
|
||||
sx={{
|
||||
mt: 2,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
backgroundImage: `linear-gradient(rgb(0 0 0/10%) 0 0)`
|
||||
},
|
||||
'&:disabled': {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
backgroundImage: `linear-gradient(rgb(0 0 0/50%) 0 0)`
|
||||
}
|
||||
}}
|
||||
loading={loading}
|
||||
variant='contained'
|
||||
fullWidth
|
||||
color='secondary'
|
||||
onClick={() => {
|
||||
setLoading(true)
|
||||
executeCustomFunctionNodeApi.request({ javascriptFunction: inputValue })
|
||||
}}
|
||||
>
|
||||
Execute
|
||||
</LoadingButton>
|
||||
)}
|
||||
{codeExecutedResult && (
|
||||
<div style={{ marginTop: '15px' }}>
|
||||
<CodeEditor
|
||||
disabled={true}
|
||||
value={codeExecutedResult}
|
||||
height='max-content'
|
||||
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||
lang={'js'}
|
||||
basicSetup={{ lineNumbers: false, foldGutter: false, autocompletion: false, highlightActiveLine: false }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onCancel}>{dialogProps.cancelButtonName}</Button>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import CodeMirror from '@uiw/react-codemirror'
|
||||
import { javascript } from '@codemirror/lang-javascript'
|
||||
import { json } from '@codemirror/lang-json'
|
||||
import { vscodeDark } from '@uiw/codemirror-theme-vscode'
|
||||
import { sublime } from '@uiw/codemirror-theme-sublime'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
|
||||
export const CodeEditor = ({ value, height, theme, lang, placeholder, disabled = false, basicSetup = {}, onValueChange }) => {
|
||||
const customStyle = EditorView.baseTheme({
|
||||
'&': {
|
||||
color: '#191b1f',
|
||||
padding: '10px'
|
||||
},
|
||||
'.cm-placeholder': {
|
||||
color: 'rgba(120, 120, 120, 0.5)'
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<CodeMirror
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
height={height ?? 'calc(100vh - 220px)'}
|
||||
theme={theme === 'dark' ? (lang === 'js' ? vscodeDark : sublime) : 'none'}
|
||||
extensions={
|
||||
lang === 'js'
|
||||
? [javascript({ jsx: true }), EditorView.lineWrapping, customStyle]
|
||||
: [json(), EditorView.lineWrapping, customStyle]
|
||||
}
|
||||
onChange={onValueChange}
|
||||
readOnly={disabled}
|
||||
editable={!disabled}
|
||||
basicSetup={basicSetup}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
CodeEditor.propTypes = {
|
||||
value: PropTypes.string,
|
||||
height: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
lang: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
basicSetup: PropTypes.object,
|
||||
onValueChange: PropTypes.func
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import Editor from 'react-simple-code-editor'
|
||||
import { highlight, languages } from 'prismjs/components/prism-core'
|
||||
import 'prismjs/components/prism-clike'
|
||||
import 'prismjs/components/prism-javascript'
|
||||
import 'prismjs/components/prism-json'
|
||||
import 'prismjs/components/prism-markup'
|
||||
import './prism-dark.css'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
export const DarkCodeEditor = ({ value, placeholder, disabled = false, type, style, onValueChange, onMouseUp, onBlur }) => {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<Editor
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
highlight={(code) => highlight(code, type === 'json' ? languages.json : languages.js)}
|
||||
padding={10}
|
||||
onValueChange={onValueChange}
|
||||
onMouseUp={onMouseUp}
|
||||
onBlur={onBlur}
|
||||
tabSize={4}
|
||||
style={{
|
||||
...style,
|
||||
background: theme.palette.codeEditor.main
|
||||
}}
|
||||
textareaClassName='editor__textarea'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
DarkCodeEditor.propTypes = {
|
||||
value: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
type: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
onValueChange: PropTypes.func,
|
||||
onMouseUp: PropTypes.func,
|
||||
onBlur: PropTypes.func
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import Editor from 'react-simple-code-editor'
|
||||
import { highlight, languages } from 'prismjs/components/prism-core'
|
||||
import 'prismjs/components/prism-clike'
|
||||
import 'prismjs/components/prism-javascript'
|
||||
import 'prismjs/components/prism-json'
|
||||
import 'prismjs/components/prism-markup'
|
||||
import './prism-light.css'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
export const LightCodeEditor = ({ value, placeholder, disabled = false, type, style, onValueChange, onMouseUp, onBlur }) => {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<Editor
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
highlight={(code) => highlight(code, type === 'json' ? languages.json : languages.js)}
|
||||
padding={10}
|
||||
onValueChange={onValueChange}
|
||||
onMouseUp={onMouseUp}
|
||||
onBlur={onBlur}
|
||||
tabSize={4}
|
||||
style={{
|
||||
...style,
|
||||
background: theme.palette.card.main
|
||||
}}
|
||||
textareaClassName='editor__textarea'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
LightCodeEditor.propTypes = {
|
||||
value: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
type: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
onValueChange: PropTypes.func,
|
||||
onMouseUp: PropTypes.func,
|
||||
onBlur: PropTypes.func
|
||||
}
|
||||
|
|
@ -1,275 +0,0 @@
|
|||
pre[class*='language-'],
|
||||
code[class*='language-'] {
|
||||
color: #d4d4d4;
|
||||
font-size: 13px;
|
||||
text-shadow: none;
|
||||
font-family: Menlo, Monaco, Consolas, 'Andale Mono', 'Ubuntu Mono', 'Courier New', monospace;
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
line-height: 1.5;
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*='language-']::selection,
|
||||
code[class*='language-']::selection,
|
||||
pre[class*='language-'] *::selection,
|
||||
code[class*='language-'] *::selection {
|
||||
text-shadow: none;
|
||||
background: #264f78;
|
||||
}
|
||||
|
||||
@media print {
|
||||
pre[class*='language-'],
|
||||
code[class*='language-'] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
pre[class*='language-'] {
|
||||
padding: 1em;
|
||||
margin: 0.5em 0;
|
||||
overflow: auto;
|
||||
background: #1e1e1e;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*='language-'] {
|
||||
padding: 0.1em 0.3em;
|
||||
border-radius: 0.3em;
|
||||
color: #db4c69;
|
||||
background: #1e1e1e;
|
||||
}
|
||||
/*********************************************************
|
||||
* Tokens
|
||||
*/
|
||||
.namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.token.doctype .token.doctype-tag {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.doctype .token.name {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog {
|
||||
color: #6a9955;
|
||||
}
|
||||
|
||||
.token.punctuation,
|
||||
.language-html .language-css .token.punctuation,
|
||||
.language-html .language-javascript .token.punctuation {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.inserted,
|
||||
.token.unit {
|
||||
color: #b5cea8;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.deleted {
|
||||
color: #ce9178;
|
||||
}
|
||||
|
||||
.language-css .token.string.url {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.token.operator.arrow {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.atrule {
|
||||
color: #ce9178;
|
||||
}
|
||||
|
||||
.token.atrule .token.rule {
|
||||
color: #c586c0;
|
||||
}
|
||||
|
||||
.token.atrule .token.url {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.atrule .token.url .token.function {
|
||||
color: #dcdcaa;
|
||||
}
|
||||
|
||||
.token.atrule .token.url .token.punctuation {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.token.keyword {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.keyword.module,
|
||||
.token.keyword.control-flow {
|
||||
color: #c586c0;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.function .token.maybe-class-name {
|
||||
color: #dcdcaa;
|
||||
}
|
||||
|
||||
.token.regex {
|
||||
color: #d16969;
|
||||
}
|
||||
|
||||
.token.important {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.constant {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.class-name,
|
||||
.token.maybe-class-name {
|
||||
color: #4ec9b0;
|
||||
}
|
||||
|
||||
.token.console {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.parameter {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.interpolation {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.punctuation.interpolation-punctuation {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.boolean {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.variable,
|
||||
.token.imports .token.maybe-class-name,
|
||||
.token.exports .token.maybe-class-name {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.selector {
|
||||
color: #d7ba7d;
|
||||
}
|
||||
|
||||
.token.escape {
|
||||
color: #d7ba7d;
|
||||
}
|
||||
|
||||
.token.tag {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.tag .token.punctuation {
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
.token.cdata {
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
.token.attr-name {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
.token.attr-value,
|
||||
.token.attr-value .token.punctuation {
|
||||
color: #ce9178;
|
||||
}
|
||||
|
||||
.token.attr-value .token.punctuation.attr-equals {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.token.namespace {
|
||||
color: #4ec9b0;
|
||||
}
|
||||
/*********************************************************
|
||||
* Language Specific
|
||||
*/
|
||||
|
||||
pre[class*='language-javascript'],
|
||||
code[class*='language-javascript'],
|
||||
pre[class*='language-jsx'],
|
||||
code[class*='language-jsx'],
|
||||
pre[class*='language-typescript'],
|
||||
code[class*='language-typescript'],
|
||||
pre[class*='language-tsx'],
|
||||
code[class*='language-tsx'] {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
|
||||
pre[class*='language-css'],
|
||||
code[class*='language-css'] {
|
||||
color: #ce9178;
|
||||
}
|
||||
|
||||
pre[class*='language-html'],
|
||||
code[class*='language-html'] {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.language-regex .token.anchor {
|
||||
color: #dcdcaa;
|
||||
}
|
||||
|
||||
.language-html .token.punctuation {
|
||||
color: #808080;
|
||||
}
|
||||
/*********************************************************
|
||||
* Line highlighting
|
||||
*/
|
||||
pre[class*='language-'] > code[class*='language-'] {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.line-highlight.line-highlight {
|
||||
background: #f7ebc6;
|
||||
box-shadow: inset 5px 0 0 #f7d87c;
|
||||
z-index: 0;
|
||||
}
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
color: #90a4ae;
|
||||
background: #fafafa;
|
||||
font-family: Roboto Mono, monospace;
|
||||
font-size: 1em;
|
||||
line-height: 1.5em;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
code[class*='language-']::-moz-selection,
|
||||
pre[class*='language-']::-moz-selection,
|
||||
code[class*='language-'] ::-moz-selection,
|
||||
pre[class*='language-'] ::-moz-selection {
|
||||
background: #cceae7;
|
||||
color: #263238;
|
||||
}
|
||||
|
||||
code[class*='language-']::selection,
|
||||
pre[class*='language-']::selection,
|
||||
code[class*='language-'] ::selection,
|
||||
pre[class*='language-'] ::selection {
|
||||
background: #cceae7;
|
||||
color: #263238;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*='language-'] {
|
||||
white-space: normal;
|
||||
border-radius: 0.2em;
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
pre[class*='language-'] {
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
margin: 0.5em 0;
|
||||
padding: 1.25em 1em;
|
||||
}
|
||||
|
||||
.language-css > code,
|
||||
.language-sass > code,
|
||||
.language-scss > code {
|
||||
color: #f76d47;
|
||||
}
|
||||
|
||||
[class*='language-'] .namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.token.atrule {
|
||||
color: #7c4dff;
|
||||
}
|
||||
|
||||
.token.attr-name {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.attr-value {
|
||||
color: #f6a434;
|
||||
}
|
||||
|
||||
.token.attribute {
|
||||
color: #f6a434;
|
||||
}
|
||||
|
||||
.token.boolean {
|
||||
color: #7c4dff;
|
||||
}
|
||||
|
||||
.token.builtin {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.cdata {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.char {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.class {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.class-name {
|
||||
color: #6182b8;
|
||||
}
|
||||
|
||||
.token.comment {
|
||||
color: #aabfc9;
|
||||
}
|
||||
|
||||
.token.constant {
|
||||
color: #7c4dff;
|
||||
}
|
||||
|
||||
.token.deleted {
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
.token.doctype {
|
||||
color: #aabfc9;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #7c4dff;
|
||||
}
|
||||
|
||||
.token.hexcode {
|
||||
color: #f76d47;
|
||||
}
|
||||
|
||||
.token.id {
|
||||
color: #7c4dff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.important {
|
||||
color: #7c4dff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.keyword {
|
||||
color: #7c4dff;
|
||||
}
|
||||
|
||||
.token.number {
|
||||
color: #f76d47;
|
||||
}
|
||||
|
||||
.token.operator {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.prolog {
|
||||
color: #aabfc9;
|
||||
}
|
||||
|
||||
.token.property {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.pseudo-class {
|
||||
color: #f6a434;
|
||||
}
|
||||
|
||||
.token.pseudo-element {
|
||||
color: #f6a434;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #39adb5;
|
||||
}
|
||||
|
||||
.token.regex {
|
||||
color: #6182b8;
|
||||
}
|
||||
|
||||
.token.selector {
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
.token.string {
|
||||
color: #f6a434;
|
||||
}
|
||||
|
||||
.token.symbol {
|
||||
color: #7c4dff;
|
||||
}
|
||||
|
||||
.token.tag {
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
.token.unit {
|
||||
color: #f76d47;
|
||||
}
|
||||
|
||||
.token.url {
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
.token.variable {
|
||||
color: #e53935;
|
||||
}
|
||||
|
|
@ -1,23 +1,10 @@
|
|||
import { useState, useEffect, useRef } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { FormControl, OutlinedInput, Popover } from '@mui/material'
|
||||
import ExpandTextDialog from 'ui-component/dialog/ExpandTextDialog'
|
||||
import SelectVariable from 'ui-component/json/SelectVariable'
|
||||
import { getAvailableNodesForVariable } from 'utils/genericHelper'
|
||||
|
||||
export const Input = ({
|
||||
inputParam,
|
||||
value,
|
||||
nodes,
|
||||
edges,
|
||||
nodeId,
|
||||
onChange,
|
||||
disabled = false,
|
||||
showDialog,
|
||||
dialogProps,
|
||||
onDialogCancel,
|
||||
onDialogConfirm
|
||||
}) => {
|
||||
export const Input = ({ inputParam, value, nodes, edges, nodeId, onChange, disabled = false }) => {
|
||||
const [myValue, setMyValue] = useState(value ?? '')
|
||||
const [anchorEl, setAnchorEl] = useState(null)
|
||||
const [availableNodesForVariable, setAvailableNodesForVariable] = useState([])
|
||||
|
|
@ -86,17 +73,6 @@ export const Input = ({
|
|||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
{showDialog && (
|
||||
<ExpandTextDialog
|
||||
show={showDialog}
|
||||
dialogProps={dialogProps}
|
||||
onCancel={onDialogCancel}
|
||||
onConfirm={(newValue, inputParamName) => {
|
||||
setMyValue(newValue)
|
||||
onDialogConfirm(newValue, inputParamName)
|
||||
}}
|
||||
></ExpandTextDialog>
|
||||
)}
|
||||
<div ref={ref}></div>
|
||||
{inputParam?.acceptVariable && (
|
||||
<Popover
|
||||
|
|
@ -131,11 +107,7 @@ Input.propTypes = {
|
|||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
onChange: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
showDialog: PropTypes.bool,
|
||||
dialogProps: PropTypes.object,
|
||||
nodes: PropTypes.array,
|
||||
edges: PropTypes.array,
|
||||
nodeId: PropTypes.string,
|
||||
onDialogCancel: PropTypes.func,
|
||||
onDialogConfirm: PropTypes.func
|
||||
nodeId: PropTypes.string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,12 @@ const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectA
|
|||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
sx={{ ml: 1 }}
|
||||
primary={node.data.inputs.chainName ? node.data.inputs.chainName : node.data.id}
|
||||
primary={
|
||||
node.data.inputs.chainName ??
|
||||
node.data.inputs.functionName ??
|
||||
node.data.inputs.variableName ??
|
||||
node.data.id
|
||||
}
|
||||
secondary={`${selectedOutputAnchor?.label ?? 'output'} from ${node.data.label}`}
|
||||
/>
|
||||
</ListItem>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,11 @@ import { flowContext } from 'store/context/ReactFlowContext'
|
|||
import { isValidConnection } from 'utils/genericHelper'
|
||||
import { JsonEditorInput } from 'ui-component/json/JsonEditor'
|
||||
import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
||||
import { CodeEditor } from 'ui-component/editor/CodeEditor'
|
||||
|
||||
import ToolDialog from 'views/tools/ToolDialog'
|
||||
import AssistantDialog from 'views/assistants/AssistantDialog'
|
||||
import ExpandTextDialog from 'ui-component/dialog/ExpandTextDialog'
|
||||
import FormatPromptValuesDialog from 'ui-component/dialog/FormatPromptValuesDialog'
|
||||
import CredentialInputHandler from './CredentialInputHandler'
|
||||
|
||||
|
|
@ -83,7 +86,7 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
|||
}
|
||||
}
|
||||
}
|
||||
const onFormatPromptValuesClicked = (value, inputParam) => {
|
||||
const onEditJSONClicked = (value, inputParam) => {
|
||||
// Preset values if the field is format prompt values
|
||||
let inputValue = value
|
||||
if (inputParam.name === 'promptValues' && !value) {
|
||||
|
|
@ -255,7 +258,7 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
|||
{inputParam.description && <TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />}
|
||||
</Typography>
|
||||
<div style={{ flexGrow: 1 }}></div>
|
||||
{inputParam.type === 'string' && inputParam.rows && (
|
||||
{((inputParam.type === 'string' && inputParam.rows) || inputParam.type === 'code') && (
|
||||
<IconButton
|
||||
size='small'
|
||||
sx={{
|
||||
|
|
@ -324,6 +327,23 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
|||
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)}
|
||||
/>
|
||||
)}
|
||||
{inputParam.type === 'code' && (
|
||||
<>
|
||||
<div style={{ height: '5px' }}></div>
|
||||
<div style={{ height: '200px' }}>
|
||||
<CodeEditor
|
||||
disabled={disabled}
|
||||
value={data.inputs[inputParam.name] ?? inputParam.default ?? ''}
|
||||
height='200px'
|
||||
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||
lang={'js'}
|
||||
placeholder={inputParam.placeholder}
|
||||
onValueChange={(code) => (data.inputs[inputParam.name] = code)}
|
||||
basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && (
|
||||
<Input
|
||||
key={data.inputs[inputParam.name]}
|
||||
|
|
@ -334,10 +354,6 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
|||
nodes={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getNodes() : []}
|
||||
edges={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getEdges() : []}
|
||||
nodeId={data.id}
|
||||
showDialog={showExpandDialog}
|
||||
dialogProps={expandDialogProps}
|
||||
onDialogCancel={() => setShowExpandDialog(false)}
|
||||
onDialogConfirm={(newValue, inputParamName) => onExpandDialogSave(newValue, inputParamName)}
|
||||
/>
|
||||
)}
|
||||
{inputParam.type === 'json' && (
|
||||
|
|
@ -353,11 +369,12 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
|||
{inputParam?.acceptVariable && (
|
||||
<>
|
||||
<Button
|
||||
sx={{ borderRadius: 25, width: '100%', mb: 2, mt: 2 }}
|
||||
sx={{ borderRadius: 25, width: '100%', mb: 0, mt: 2 }}
|
||||
variant='outlined'
|
||||
onClick={() => onFormatPromptValuesClicked(data.inputs[inputParam.name] ?? '', inputParam)}
|
||||
disabled={disabled}
|
||||
onClick={() => onEditJSONClicked(data.inputs[inputParam.name] ?? '', inputParam)}
|
||||
>
|
||||
Format Prompt Values
|
||||
{inputParam.label}
|
||||
</Button>
|
||||
<FormatPromptValuesDialog
|
||||
show={showFormatPromptValuesDialog}
|
||||
|
|
@ -428,6 +445,12 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
|||
onCancel={() => setAsyncOptionEditDialog('')}
|
||||
onConfirm={onConfirmAsyncOption}
|
||||
></AssistantDialog>
|
||||
<ExpandTextDialog
|
||||
show={showExpandDialog}
|
||||
dialogProps={expandDialogProps}
|
||||
onCancel={() => setShowExpandDialog(false)}
|
||||
onConfirm={(newValue, inputParamName) => onExpandDialogSave(newValue, inputParamName)}
|
||||
></ExpandTextDialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
|||
import { GridActionsCellItem } from '@mui/x-data-grid'
|
||||
import DeleteIcon from '@mui/icons-material/Delete'
|
||||
import ConfirmDialog from 'ui-component/dialog/ConfirmDialog'
|
||||
import { DarkCodeEditor } from 'ui-component/editor/DarkCodeEditor'
|
||||
import { LightCodeEditor } from 'ui-component/editor/LightCodeEditor'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import { CodeEditor } from 'ui-component/editor/CodeEditor'
|
||||
|
||||
// Icons
|
||||
import { IconX, IconFileExport } from '@tabler/icons'
|
||||
|
|
@ -56,7 +54,6 @@ try {
|
|||
|
||||
const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) => {
|
||||
const portalElement = document.getElementById('portal')
|
||||
const theme = useTheme()
|
||||
|
||||
const customization = useSelector((state) => state.customization)
|
||||
const dispatch = useDispatch()
|
||||
|
|
@ -490,32 +487,14 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
|
|||
See Example
|
||||
</Button>
|
||||
)}
|
||||
{customization.isDarkMode ? (
|
||||
<DarkCodeEditor
|
||||
value={toolFunc}
|
||||
disabled={dialogProps.type === 'TEMPLATE'}
|
||||
onValueChange={(code) => setToolFunc(code)}
|
||||
style={{
|
||||
fontSize: '0.875rem',
|
||||
minHeight: 'calc(100vh - 220px)',
|
||||
width: '100%',
|
||||
borderRadius: 5
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<LightCodeEditor
|
||||
value={toolFunc}
|
||||
disabled={dialogProps.type === 'TEMPLATE'}
|
||||
onValueChange={(code) => setToolFunc(code)}
|
||||
style={{
|
||||
fontSize: '0.875rem',
|
||||
minHeight: 'calc(100vh - 220px)',
|
||||
width: '100%',
|
||||
border: `1px solid ${theme.palette.grey[300]}`,
|
||||
borderRadius: 5
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<CodeEditor
|
||||
disabled={dialogProps.type === 'TEMPLATE'}
|
||||
value={toolFunc}
|
||||
height='calc(100vh - 220px)'
|
||||
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||
lang={'js'}
|
||||
onValueChange={(code) => setToolFunc(code)}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
|
|
|||