From caffad0fb0f8ff8d57f06de05f2affa5cbbe40e6 Mon Sep 17 00:00:00 2001 From: Ong Chung Yau <33013947+chungyau97@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:51:14 +0800 Subject: [PATCH 1/2] chore:variable (#4946) --- .../server/src/services/export-import/index.ts | 3 +++ packages/server/src/services/variables/index.ts | 16 ++++++++++++---- .../views/variables/AddEditVariableDialog.jsx | 6 +++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/server/src/services/export-import/index.ts b/packages/server/src/services/export-import/index.ts index 0f60796a5..0fb86e00d 100644 --- a/packages/server/src/services/export-import/index.ts +++ b/packages/server/src/services/export-import/index.ts @@ -25,6 +25,7 @@ import executionService, { ExecutionFilters } from '../executions' import marketplacesService from '../marketplaces' import toolsService from '../tools' import variableService from '../variables' +import { Platform } from '../../Interface' type ExportInput = { agentflow: boolean @@ -547,6 +548,8 @@ async function replaceDuplicateIdsForVariable(queryRunner: QueryRunner, original const records = await queryRunner.manager.find(Variable, { where: { id: In(ids) } }) + if (getRunningExpressApp().identityManager.getPlatformType() === Platform.CLOUD) + originalData.Variable = originalData.Variable.filter((variable) => variable.type !== 'runtime') if (records.length < 0) return originalData for (let record of records) { const oldId = record.id diff --git a/packages/server/src/services/variables/index.ts b/packages/server/src/services/variables/index.ts index 0a0099842..b2ecc31c5 100644 --- a/packages/server/src/services/variables/index.ts +++ b/packages/server/src/services/variables/index.ts @@ -6,11 +6,13 @@ import { getErrorMessage } from '../../errors/utils' import { getAppVersion } from '../../utils' import { QueryRunner } from 'typeorm' import { validate } from 'uuid' +import { Platform } from '../../Interface' const createVariable = async (newVariable: Variable, orgId: string) => { + const appServer = getRunningExpressApp() + if (appServer.identityManager.getPlatformType() === Platform.CLOUD && newVariable.type === 'runtime') + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'Cloud platform does not support runtime variables!') try { - const appServer = getRunningExpressApp() - const variable = await appServer.AppDataSource.getRepository(Variable).create(newVariable) const dbResponse = await appServer.AppDataSource.getRepository(Variable).save(variable) await appServer.telemetry.sendTelemetry( @@ -87,8 +89,10 @@ const getVariableById = async (variableId: string) => { } const updateVariable = async (variable: Variable, updatedVariable: Variable) => { + const appServer = getRunningExpressApp() + if (appServer.identityManager.getPlatformType() === Platform.CLOUD && updatedVariable.type === 'runtime') + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'Cloud platform does not support runtime variables!') try { - const appServer = getRunningExpressApp() const tmpUpdatedVariable = await appServer.AppDataSource.getRepository(Variable).merge(variable, updatedVariable) const dbResponse = await appServer.AppDataSource.getRepository(Variable).save(tmpUpdatedVariable) return dbResponse @@ -131,7 +135,7 @@ const importVariables = async (newVariables: Partial[], queryRunner?: }) // step 3 - remove ids that are only duplicate - const prepVariables: Partial[] = newVariables.map((newVariable) => { + let prepVariables: Partial[] = newVariables.map((newVariable) => { let id: string = '' if (newVariable.id) id = newVariable.id if (foundIds.includes(id)) { @@ -141,6 +145,10 @@ const importVariables = async (newVariables: Partial[], queryRunner?: return newVariable }) + // Filter out variables with type "runtime" + if (appServer.identityManager.getPlatformType() === Platform.CLOUD) + prepVariables = prepVariables.filter((variable) => variable.type !== 'runtime') + // step 4 - transactional insert array of entities const insertResponse = await repository.insert(prepVariables) diff --git a/packages/ui/src/views/variables/AddEditVariableDialog.jsx b/packages/ui/src/views/variables/AddEditVariableDialog.jsx index 9647ffc04..dd82c7560 100644 --- a/packages/ui/src/views/variables/AddEditVariableDialog.jsx +++ b/packages/ui/src/views/variables/AddEditVariableDialog.jsx @@ -114,7 +114,7 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm, setErro if (setError) setError(err) enqueueSnackbar({ message: `Failed to add new Variable: ${ - typeof error.response.data === 'object' ? error.response.data.message : error.response.data + typeof err.response.data === 'object' ? err.response.data.message : err.response.data }`, options: { key: new Date().getTime() + Math.random(), @@ -155,11 +155,11 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm, setErro }) onConfirm(saveResp.data.id) } - } catch (error) { + } catch (err) { if (setError) setError(err) enqueueSnackbar({ message: `Failed to save Variable: ${ - typeof error.response.data === 'object' ? error.response.data.message : error.response.data + typeof err.response.data === 'object' ? err.response.data.message : err.response.data }`, options: { key: new Date().getTime() + Math.random(), From 221ac9b25dc9ab0c2fdb31c7d24b2b72b51b6814 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 25 Jul 2025 13:37:33 +0100 Subject: [PATCH 2/2] Feature/Allow overrideconfig from executeflow node to take in variables (#4947) * allow overrideconfig from executeflow node to take in variables * update array object schema --- .../agentflow/ExecuteFlow/ExecuteFlow.ts | 22 ++++++++++++------- packages/server/src/utils/index.ts | 12 ++++------ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/components/nodes/agentflow/ExecuteFlow/ExecuteFlow.ts b/packages/components/nodes/agentflow/ExecuteFlow/ExecuteFlow.ts index edc720531..ebb5ac36f 100644 --- a/packages/components/nodes/agentflow/ExecuteFlow/ExecuteFlow.ts +++ b/packages/components/nodes/agentflow/ExecuteFlow/ExecuteFlow.ts @@ -30,7 +30,7 @@ class ExecuteFlow_Agentflow implements INode { constructor() { this.label = 'Execute Flow' this.name = 'executeFlowAgentflow' - this.version = 1.0 + this.version = 1.1 this.type = 'ExecuteFlow' this.category = 'Agent Flows' this.description = 'Execute another flow' @@ -62,7 +62,8 @@ class ExecuteFlow_Agentflow implements INode { name: 'executeFlowOverrideConfig', description: 'Override the config passed to the flow', type: 'json', - optional: true + optional: true, + acceptVariable: true }, { label: 'Base URL', @@ -162,12 +163,17 @@ class ExecuteFlow_Agentflow implements INode { const flowInput = nodeData.inputs?.executeFlowInput as string const returnResponseAs = nodeData.inputs?.executeFlowReturnResponseAs as string const _executeFlowUpdateState = nodeData.inputs?.executeFlowUpdateState - const overrideConfig = - typeof nodeData.inputs?.executeFlowOverrideConfig === 'string' && - nodeData.inputs.executeFlowOverrideConfig.startsWith('{') && - nodeData.inputs.executeFlowOverrideConfig.endsWith('}') - ? JSON.parse(nodeData.inputs.executeFlowOverrideConfig) - : nodeData.inputs?.executeFlowOverrideConfig + + let overrideConfig = nodeData.inputs?.executeFlowOverrideConfig + if (typeof overrideConfig === 'string' && overrideConfig.startsWith('{') && overrideConfig.endsWith('}')) { + try { + // Handle escaped square brackets and other common escape sequences + const unescapedConfig = overrideConfig.replace(/\\(\[|\])/g, '$1') + overrideConfig = JSON.parse(unescapedConfig) + } catch (parseError) { + throw new Error(`Invalid JSON in executeFlowOverrideConfig: ${parseError.message}`) + } + } const state = options.agentflowRuntime?.state as ICommonObject const runtimeChatHistory = (options.agentflowRuntime?.chatHistory as BaseMessageLike[]) ?? [] diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 89aa4e3b7..d99c0b546 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -1378,11 +1378,10 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component } continue } else if (inputParam.type === 'array') { - // get array item schema const arrayItem = inputParam.array if (Array.isArray(arrayItem)) { - const arraySchema = [] - // Each array item is a field definition + const arrayItemSchema: Record = {} + // Build object schema representing the structure of each array item for (const item of arrayItem) { let itemType = item.type if (itemType === 'options') { @@ -1391,10 +1390,7 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component } else if (itemType === 'file') { itemType = item.fileType ?? item.type } - arraySchema.push({ - name: item.name, - type: itemType - }) + arrayItemSchema[item.name] = itemType } obj = { node: flowNode.data.label, @@ -1402,7 +1398,7 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component label: inputParam.label, name: inputParam.name, type: inputParam.type, - schema: arraySchema + schema: arrayItemSchema } } } else if (inputParam.loadConfig) {