Feature/Add ability to get vars from text input (#2986)

add ability to get vars from text input
This commit is contained in:
Henry Heng
2024-08-09 17:31:21 +01:00
committed by GitHub
parent d1da628b7c
commit 376e644cec
4 changed files with 118 additions and 15 deletions
+3 -3
View File
@@ -485,7 +485,7 @@ const compileMultiAgentsGraph = async (
let flowNodeData = cloneDeep(workerNode.data)
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
flowNodeData = resolveVariables(flowNodeData, reactflowNodes, question, chatHistory)
flowNodeData = await resolveVariables(appServer.AppDataSource, flowNodeData, reactflowNodes, question, chatHistory, overrideConfig)
try {
const workerResult: IMultiAgentNode = await newNodeInstance.init(flowNodeData, question, options)
@@ -516,7 +516,7 @@ const compileMultiAgentsGraph = async (
let flowNodeData = cloneDeep(supervisorNode.data)
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]
@@ -676,7 +676,7 @@ const compileSeqAgentsGraph = async (
flowNodeData = cloneDeep(node.data)
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)
return seqAgentNode
+8 -1
View File
@@ -328,7 +328,14 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
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
appServer.chatflowPool.add(chatflowid, nodeToExecuteData, startingNodes, incomingInput?.overrideConfig)
+93 -10
View File
@@ -503,7 +503,14 @@ export const buildFlow = async ({
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) {
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
* @param {string} paramValue
@@ -699,12 +753,14 @@ export const clearSessionMemory = async (
* @param {boolean} isAcceptVariable
* @returns {string}
*/
export const getVariableValue = (
export const getVariableValue = async (
appDataSource: DataSource,
paramValue: string | object,
reactFlowNodes: IReactFlowNode[],
question: string,
chatHistory: IMessage[],
isAcceptVariable = false
isAcceptVariable = false,
overrideConfig?: ICommonObject
) => {
const isObject = typeof paramValue === 'object'
let returnVal = (isObject ? JSON.stringify(paramValue) : paramValue) ?? ''
@@ -740,6 +796,15 @@ export const getVariableValue = (
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.
// 1: <variableNodeId>.data.instance
// 2: <variableNodeId>.data.instance.pathtokey
@@ -826,35 +891,53 @@ export const getVariableValue = (
* @param {string} question
* @returns {INodeData}
*/
export const resolveVariables = (
export const resolveVariables = async (
appDataSource: DataSource,
reactFlowNodeData: INodeData,
reactFlowNodes: IReactFlowNode[],
question: string,
chatHistory: IMessage[]
): INodeData => {
chatHistory: IMessage[],
overrideConfig?: ICommonObject
): Promise<INodeData> => {
let flowNodeData = cloneDeep(reactFlowNodeData)
const types = 'inputs'
const getParamValues = (paramsObj: ICommonObject) => {
const getParamValues = async (paramsObj: ICommonObject) => {
for (const key in paramsObj) {
const paramValue: string = paramsObj[key]
if (Array.isArray(paramValue)) {
const resolvedInstances = []
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)
}
paramsObj[key] = resolvedInstances
} else {
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
}
}
}
const paramsObj = flowNodeData[types] ?? {}
getParamValues(paramsObj)
await getParamValues(paramsObj)
return flowNodeData
}