Bugfix/config input for multiple same fields (#4548)

* fix config input for multiple same fields

* fix custom tool not selected
This commit is contained in:
Henry Heng 2025-05-31 17:03:03 +01:00 committed by GitHub
parent eb69b23d73
commit a88337cc83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 43 additions and 32 deletions

View File

@ -28,7 +28,7 @@ class Tool_Agentflow implements INode {
constructor() {
this.label = 'Tool'
this.name = 'toolAgentflow'
this.version = 1.0
this.version = 1.1
this.type = 'Tool'
this.category = 'Agent Flows'
this.description = 'Tools allow LLM to interact with external systems'
@ -37,7 +37,7 @@ class Tool_Agentflow implements INode {
this.inputs = [
{
label: 'Tool',
name: 'selectedTool',
name: 'toolAgentflowSelectedTool',
type: 'asyncOptions',
loadMethod: 'listTools',
loadConfig: true
@ -64,7 +64,7 @@ class Tool_Agentflow implements INode {
}
],
show: {
selectedTool: '.+'
toolAgentflowSelectedTool: '.+'
}
},
{
@ -124,7 +124,7 @@ class Tool_Agentflow implements INode {
},
async listToolInputArgs(nodeData: INodeData, options: ICommonObject): Promise<INodeOptionsValue[]> {
const currentNode = options.currentNode as ICommonObject
const selectedTool = currentNode?.inputs?.selectedTool as string
const selectedTool = (currentNode?.inputs?.selectedTool as string) || (currentNode?.inputs?.toolAgentflowSelectedTool as string)
const selectedToolConfig = currentNode?.inputs?.selectedToolConfig as ICommonObject
const nodeInstanceFilePath = options.componentNodes[selectedTool].filePath as string
@ -183,7 +183,7 @@ class Tool_Agentflow implements INode {
}
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
const selectedTool = nodeData.inputs?.selectedTool as string
const selectedTool = (nodeData.inputs?.selectedTool as string) || (nodeData.inputs?.toolAgentflowSelectedTool as string)
const selectedToolConfig = nodeData.inputs?.selectedToolConfig as ICommonObject
const toolInputArgs = nodeData.inputs?.toolInputArgs as IToolInputArgs[]

View File

@ -526,7 +526,7 @@
"data": {
"id": "toolAgentflow_0",
"label": "Slack Reply",
"version": 1,
"version": 1.1,
"name": "toolAgentflow",
"type": "Tool",
"color": "#d4a373",
@ -536,11 +536,11 @@
"inputParams": [
{
"label": "Tool",
"name": "selectedTool",
"name": "toolAgentflowSelectedTool",
"type": "asyncOptions",
"loadMethod": "listTools",
"loadConfig": true,
"id": "toolAgentflow_0-input-selectedTool-asyncOptions",
"id": "toolAgentflow_0-input-toolAgentflowSelectedTool-asyncOptions",
"display": true
},
{
@ -565,7 +565,7 @@
}
],
"show": {
"selectedTool": ".+"
"toolAgentflowSelectedTool": ".+"
},
"id": "toolAgentflow_0-input-toolInputArgs-array",
"display": true
@ -599,7 +599,7 @@
],
"inputAnchors": [],
"inputs": {
"selectedTool": "slackMCP",
"toolAgentflowSelectedTool": "slackMCP",
"toolInputArgs": [
{
"inputArgName": "channel_id",
@ -611,9 +611,9 @@
}
],
"toolUpdateState": "",
"selectedToolConfig": {
"toolAgentflowSelectedToolConfig": {
"mcpActions": "[\"slack_post_message\"]",
"selectedTool": "slackMCP"
"toolAgentflowSelectedTool": "slackMCP"
}
},
"outputAnchors": [

View File

@ -1,4 +1,4 @@
import { useContext, useState, useEffect, useRef } from 'react'
import { useContext, useState, useEffect, useMemo } from 'react'
import PropTypes from 'prop-types'
import { cloneDeep } from 'lodash'
@ -26,8 +26,12 @@ export const ConfigInput = ({ data, inputParam, disabled = false, arrayIndex = n
const [expanded, setExpanded] = useState(false)
const [selectedComponentNodeData, setSelectedComponentNodeData] = useState({})
// Track the last processed input values to prevent infinite loops
const lastProcessedInputsRef = useRef({})
// Track the last processed input values to prevent infinite loops using useState
const [lastProcessedInputs, setLastProcessedInputs] = useState({
mainValue: null,
configValue: null,
arrayValue: null
})
const handleAccordionChange = (event, isExpanded) => {
setExpanded(isExpanded)
@ -64,6 +68,18 @@ export const ConfigInput = ({ data, inputParam, disabled = false, arrayIndex = n
setSelectedComponentNodeData(nodeData)
}
// Memoize current input values for reliable comparison
const currentInputValues = useMemo(
() => ({
mainValue: data.inputs[inputParam.name],
configValue: data.inputs[`${inputParam.name}Config`],
arrayValue: parentParamForArray ? data.inputs[parentParamForArray.name] : null
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[data.inputs, inputParam.name, parentParamForArray?.name]
)
// Load initial component data when the component mounts
useEffect(() => {
const loadComponentData = async () => {
@ -138,11 +154,11 @@ export const ConfigInput = ({ data, inputParam, disabled = false, arrayIndex = n
setSelectedComponentNodeData(componentNodeData)
// Store the processed inputs to track changes
lastProcessedInputsRef.current = {
setLastProcessedInputs({
mainValue: data.inputs[inputParam.name],
configValue: data.inputs[`${inputParam.name}Config`],
arrayValue: parentParamForArray ? data.inputs[parentParamForArray.name] : null
}
})
}
loadComponentData()
@ -154,15 +170,10 @@ export const ConfigInput = ({ data, inputParam, disabled = false, arrayIndex = n
useEffect(() => {
if (!selectedComponentNodeData.inputParams) return
// Get current input values
const currentMainValue = data.inputs[inputParam.name]
const currentConfigValue = data.inputs[`${inputParam.name}Config`]
const currentArrayValue = parentParamForArray ? data.inputs[parentParamForArray.name] : null
// Check if relevant inputs have changed
const hasMainValueChanged = lastProcessedInputsRef.current.mainValue !== currentMainValue
const hasConfigValueChanged = lastProcessedInputsRef.current.configValue !== currentConfigValue
const hasArrayValueChanged = lastProcessedInputsRef.current.arrayValue !== currentArrayValue
// Check if relevant inputs have changed using strict equality comparison
const hasMainValueChanged = lastProcessedInputs.mainValue !== currentInputValues.mainValue
const hasConfigValueChanged = lastProcessedInputs.configValue !== currentInputValues.configValue
const hasArrayValueChanged = lastProcessedInputs.arrayValue !== currentInputValues.arrayValue
if (!hasMainValueChanged && !hasConfigValueChanged && !hasArrayValueChanged) {
return // No relevant changes
@ -224,17 +235,17 @@ export const ConfigInput = ({ data, inputParam, disabled = false, arrayIndex = n
setSelectedComponentNodeData(updatedComponentData)
// Update the tracked values
lastProcessedInputsRef.current = {
mainValue: currentMainValue,
configValue: currentConfigValue,
arrayValue: currentArrayValue
}
setLastProcessedInputs({
mainValue: currentInputValues.mainValue,
configValue: currentInputValues.configValue,
arrayValue: currentInputValues.arrayValue
})
}
updateComponentData()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data.inputs, inputParam.name, parentParamForArray?.name, arrayIndex])
}, [currentInputValues, selectedComponentNodeData.inputParams, inputParam.name, parentParamForArray?.name, arrayIndex])
// Update node configuration when selected component data changes
useEffect(() => {