mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 23:01:09 +03:00
Feature/Add ability to get vars from text input (#2986)
add ability to get vars from text input
This commit is contained in:
@@ -485,7 +485,7 @@ const compileMultiAgentsGraph = async (
|
|||||||
|
|
||||||
let flowNodeData = cloneDeep(workerNode.data)
|
let flowNodeData = cloneDeep(workerNode.data)
|
||||||
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
||||||
flowNodeData = resolveVariables(flowNodeData, reactflowNodes, question, chatHistory)
|
flowNodeData = await resolveVariables(appServer.AppDataSource, flowNodeData, reactflowNodes, question, chatHistory, overrideConfig)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const workerResult: IMultiAgentNode = await newNodeInstance.init(flowNodeData, question, options)
|
const workerResult: IMultiAgentNode = await newNodeInstance.init(flowNodeData, question, options)
|
||||||
@@ -516,7 +516,7 @@ const compileMultiAgentsGraph = async (
|
|||||||
let flowNodeData = cloneDeep(supervisorNode.data)
|
let flowNodeData = cloneDeep(supervisorNode.data)
|
||||||
|
|
||||||
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
||||||
flowNodeData = resolveVariables(flowNodeData, reactflowNodes, question, chatHistory)
|
flowNodeData = await resolveVariables(appServer.AppDataSource, flowNodeData, reactflowNodes, question, chatHistory, overrideConfig)
|
||||||
|
|
||||||
if (flowNodeData.inputs) flowNodeData.inputs.workerNodes = supervisorWorkers[supervisor]
|
if (flowNodeData.inputs) flowNodeData.inputs.workerNodes = supervisorWorkers[supervisor]
|
||||||
|
|
||||||
@@ -676,7 +676,7 @@ const compileSeqAgentsGraph = async (
|
|||||||
|
|
||||||
flowNodeData = cloneDeep(node.data)
|
flowNodeData = cloneDeep(node.data)
|
||||||
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
||||||
flowNodeData = resolveVariables(flowNodeData, reactflowNodes, question, chatHistory)
|
flowNodeData = await resolveVariables(appServer.AppDataSource, flowNodeData, reactflowNodes, question, chatHistory, overrideConfig)
|
||||||
|
|
||||||
const seqAgentNode: ISeqAgentNode = await newNodeInstance.init(flowNodeData, question, options)
|
const seqAgentNode: ISeqAgentNode = await newNodeInstance.init(flowNodeData, question, options)
|
||||||
return seqAgentNode
|
return seqAgentNode
|
||||||
|
|||||||
@@ -328,7 +328,14 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
|
|||||||
nodeToExecute.data = replaceInputsWithConfig(nodeToExecute.data, incomingInput.overrideConfig)
|
nodeToExecute.data = replaceInputsWithConfig(nodeToExecute.data, incomingInput.overrideConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reactFlowNodeData: INodeData = resolveVariables(nodeToExecute.data, reactFlowNodes, incomingInput.question, chatHistory)
|
const reactFlowNodeData: INodeData = await resolveVariables(
|
||||||
|
appServer.AppDataSource,
|
||||||
|
nodeToExecute.data,
|
||||||
|
reactFlowNodes,
|
||||||
|
incomingInput.question,
|
||||||
|
chatHistory,
|
||||||
|
incomingInput.overrideConfig
|
||||||
|
)
|
||||||
nodeToExecuteData = reactFlowNodeData
|
nodeToExecuteData = reactFlowNodeData
|
||||||
|
|
||||||
appServer.chatflowPool.add(chatflowid, nodeToExecuteData, startingNodes, incomingInput?.overrideConfig)
|
appServer.chatflowPool.add(chatflowid, nodeToExecuteData, startingNodes, incomingInput?.overrideConfig)
|
||||||
|
|||||||
@@ -503,7 +503,14 @@ export const buildFlow = async ({
|
|||||||
|
|
||||||
if (isUpsert) upsertHistory['flowData'] = saveUpsertFlowData(flowNodeData, upsertHistory)
|
if (isUpsert) upsertHistory['flowData'] = saveUpsertFlowData(flowNodeData, upsertHistory)
|
||||||
|
|
||||||
const reactFlowNodeData: INodeData = resolveVariables(flowNodeData, flowNodes, question, chatHistory)
|
const reactFlowNodeData: INodeData = await resolveVariables(
|
||||||
|
appDataSource,
|
||||||
|
flowNodeData,
|
||||||
|
flowNodes,
|
||||||
|
question,
|
||||||
|
chatHistory,
|
||||||
|
overrideConfig
|
||||||
|
)
|
||||||
|
|
||||||
if (isUpsert && stopNodeId && nodeId === stopNodeId) {
|
if (isUpsert && stopNodeId && nodeId === stopNodeId) {
|
||||||
logger.debug(`[server]: Upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
logger.debug(`[server]: Upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||||
@@ -691,6 +698,53 @@ export const clearSessionMemory = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getGlobalVariable = async (appDataSource: DataSource, overrideConfig?: ICommonObject) => {
|
||||||
|
const variables = await appDataSource.getRepository(Variable).find()
|
||||||
|
|
||||||
|
// override variables defined in overrideConfig
|
||||||
|
// nodeData.inputs.vars is an Object, check each property and override the variable
|
||||||
|
if (overrideConfig?.vars) {
|
||||||
|
for (const propertyName of Object.getOwnPropertyNames(overrideConfig.vars)) {
|
||||||
|
const foundVar = variables.find((v) => v.name === propertyName)
|
||||||
|
if (foundVar) {
|
||||||
|
// even if the variable was defined as runtime, we override it with static value
|
||||||
|
foundVar.type = 'static'
|
||||||
|
foundVar.value = overrideConfig.vars[propertyName]
|
||||||
|
} else {
|
||||||
|
// add it the variables, if not found locally in the db
|
||||||
|
variables.push({
|
||||||
|
name: propertyName,
|
||||||
|
type: 'static',
|
||||||
|
value: overrideConfig.vars[propertyName],
|
||||||
|
id: '',
|
||||||
|
updatedDate: new Date(),
|
||||||
|
createdDate: new Date()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let vars = {}
|
||||||
|
if (variables.length) {
|
||||||
|
for (const item of variables) {
|
||||||
|
let value = item.value
|
||||||
|
|
||||||
|
// read from .env file
|
||||||
|
if (item.type === 'runtime') {
|
||||||
|
value = process.env[item.name] ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(vars, item.name, {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
value: value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vars
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get variable value from outputResponses.output
|
* Get variable value from outputResponses.output
|
||||||
* @param {string} paramValue
|
* @param {string} paramValue
|
||||||
@@ -699,12 +753,14 @@ export const clearSessionMemory = async (
|
|||||||
* @param {boolean} isAcceptVariable
|
* @param {boolean} isAcceptVariable
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export const getVariableValue = (
|
export const getVariableValue = async (
|
||||||
|
appDataSource: DataSource,
|
||||||
paramValue: string | object,
|
paramValue: string | object,
|
||||||
reactFlowNodes: IReactFlowNode[],
|
reactFlowNodes: IReactFlowNode[],
|
||||||
question: string,
|
question: string,
|
||||||
chatHistory: IMessage[],
|
chatHistory: IMessage[],
|
||||||
isAcceptVariable = false
|
isAcceptVariable = false,
|
||||||
|
overrideConfig?: ICommonObject
|
||||||
) => {
|
) => {
|
||||||
const isObject = typeof paramValue === 'object'
|
const isObject = typeof paramValue === 'object'
|
||||||
let returnVal = (isObject ? JSON.stringify(paramValue) : paramValue) ?? ''
|
let returnVal = (isObject ? JSON.stringify(paramValue) : paramValue) ?? ''
|
||||||
@@ -740,6 +796,15 @@ export const getVariableValue = (
|
|||||||
variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(convertChatHistoryToText(chatHistory), false)
|
variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(convertChatHistoryToText(chatHistory), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (variableFullPath.startsWith('$vars.')) {
|
||||||
|
const vars = await getGlobalVariable(appDataSource, overrideConfig)
|
||||||
|
const variableValue = get(vars, variableFullPath.replace('$vars.', ''))
|
||||||
|
if (variableValue) {
|
||||||
|
variableDict[`{{${variableFullPath}}}`] = variableValue
|
||||||
|
returnVal = returnVal.split(`{{${variableFullPath}}}`).join(variableValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve values with following case.
|
// Resolve values with following case.
|
||||||
// 1: <variableNodeId>.data.instance
|
// 1: <variableNodeId>.data.instance
|
||||||
// 2: <variableNodeId>.data.instance.pathtokey
|
// 2: <variableNodeId>.data.instance.pathtokey
|
||||||
@@ -826,35 +891,53 @@ export const getVariableValue = (
|
|||||||
* @param {string} question
|
* @param {string} question
|
||||||
* @returns {INodeData}
|
* @returns {INodeData}
|
||||||
*/
|
*/
|
||||||
export const resolveVariables = (
|
export const resolveVariables = async (
|
||||||
|
appDataSource: DataSource,
|
||||||
reactFlowNodeData: INodeData,
|
reactFlowNodeData: INodeData,
|
||||||
reactFlowNodes: IReactFlowNode[],
|
reactFlowNodes: IReactFlowNode[],
|
||||||
question: string,
|
question: string,
|
||||||
chatHistory: IMessage[]
|
chatHistory: IMessage[],
|
||||||
): INodeData => {
|
overrideConfig?: ICommonObject
|
||||||
|
): Promise<INodeData> => {
|
||||||
let flowNodeData = cloneDeep(reactFlowNodeData)
|
let flowNodeData = cloneDeep(reactFlowNodeData)
|
||||||
const types = 'inputs'
|
const types = 'inputs'
|
||||||
|
|
||||||
const getParamValues = (paramsObj: ICommonObject) => {
|
const getParamValues = async (paramsObj: ICommonObject) => {
|
||||||
for (const key in paramsObj) {
|
for (const key in paramsObj) {
|
||||||
const paramValue: string = paramsObj[key]
|
const paramValue: string = paramsObj[key]
|
||||||
if (Array.isArray(paramValue)) {
|
if (Array.isArray(paramValue)) {
|
||||||
const resolvedInstances = []
|
const resolvedInstances = []
|
||||||
for (const param of paramValue) {
|
for (const param of paramValue) {
|
||||||
const resolvedInstance = getVariableValue(param, reactFlowNodes, question, chatHistory)
|
const resolvedInstance = await getVariableValue(
|
||||||
|
appDataSource,
|
||||||
|
param,
|
||||||
|
reactFlowNodes,
|
||||||
|
question,
|
||||||
|
chatHistory,
|
||||||
|
undefined,
|
||||||
|
overrideConfig
|
||||||
|
)
|
||||||
resolvedInstances.push(resolvedInstance)
|
resolvedInstances.push(resolvedInstance)
|
||||||
}
|
}
|
||||||
paramsObj[key] = resolvedInstances
|
paramsObj[key] = resolvedInstances
|
||||||
} else {
|
} else {
|
||||||
const isAcceptVariable = reactFlowNodeData.inputParams.find((param) => param.name === key)?.acceptVariable ?? false
|
const isAcceptVariable = reactFlowNodeData.inputParams.find((param) => param.name === key)?.acceptVariable ?? false
|
||||||
const resolvedInstance = getVariableValue(paramValue, reactFlowNodes, question, chatHistory, isAcceptVariable)
|
const resolvedInstance = await getVariableValue(
|
||||||
|
appDataSource,
|
||||||
|
paramValue,
|
||||||
|
reactFlowNodes,
|
||||||
|
question,
|
||||||
|
chatHistory,
|
||||||
|
isAcceptVariable,
|
||||||
|
overrideConfig
|
||||||
|
)
|
||||||
paramsObj[key] = resolvedInstance
|
paramsObj[key] = resolvedInstance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const paramsObj = flowNodeData[types] ?? {}
|
const paramsObj = flowNodeData[types] ?? {}
|
||||||
getParamValues(paramsObj)
|
await getParamValues(paramsObj)
|
||||||
|
|
||||||
return flowNodeData
|
return flowNodeData
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ const HowToUseVariablesDialog = ({ show, onCancel }) => {
|
|||||||
How To Use Variables
|
How To Use Variables
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<p style={{ marginBottom: '10px' }}>Variables can be used in Custom Tool Function with the $ prefix.</p>
|
<p style={{ marginBottom: '10px' }}>
|
||||||
|
Variables can be used in Custom Tool, Custom Function, Custom Loader, If Else Function with the $ prefix.
|
||||||
|
</p>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
disabled={true}
|
disabled={true}
|
||||||
value={`$vars.<variable-name>`}
|
value={`$vars.<variable-name>`}
|
||||||
@@ -36,6 +38,17 @@ const HowToUseVariablesDialog = ({ show, onCancel }) => {
|
|||||||
lang={'js'}
|
lang={'js'}
|
||||||
basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }}
|
basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }}
|
||||||
/>
|
/>
|
||||||
|
<p style={{ marginBottom: '10px' }}>
|
||||||
|
Variables can also be used in Text Field parameter of any node. For example, in System Message of Agent:
|
||||||
|
</p>
|
||||||
|
<CodeEditor
|
||||||
|
disabled={true}
|
||||||
|
value={`You are a {{$vars.personality}} AI assistant`}
|
||||||
|
height={'50px'}
|
||||||
|
theme={'dark'}
|
||||||
|
lang={'js'}
|
||||||
|
basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }}
|
||||||
|
/>
|
||||||
<p style={{ marginBottom: '10px' }}>
|
<p style={{ marginBottom: '10px' }}>
|
||||||
If variable type is Static, the value will be retrieved as it is. If variable type is Runtime, the value will be
|
If variable type is Static, the value will be retrieved as it is. If variable type is Runtime, the value will be
|
||||||
retrieved from .env file.
|
retrieved from .env file.
|
||||||
|
|||||||
Reference in New Issue
Block a user