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
+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
}