fix: avoid using node_data.version for judgement tool node version (#22462)

Co-authored-by: JzoNg <jzongcode@gmail.com>
This commit is contained in:
Novice
2025-07-21 09:28:47 +08:00
committed by GitHub
parent f9f46bfcbe
commit 17a8f1a0f1
12 changed files with 44 additions and 13 deletions

View File

@@ -270,7 +270,14 @@ class AgentNode(BaseNode):
) )
extra = tool.get("extra", {}) extra = tool.get("extra", {})
runtime_variable_pool = variable_pool if self._node_data.version != "1" else None
# This is an issue that caused problems before.
# Logically, we shouldn't use the node_data.version field for judgment
# But for backward compatibility with historical data
# this version field judgment is still preserved here.
runtime_variable_pool: VariablePool | None = None
if node_data.version != "1" or node_data.tool_node_version != "1":
runtime_variable_pool = variable_pool
tool_runtime = ToolManager.get_agent_tool_runtime( tool_runtime = ToolManager.get_agent_tool_runtime(
self.tenant_id, self.app_id, entity, self.invoke_from, runtime_variable_pool self.tenant_id, self.app_id, entity, self.invoke_from, runtime_variable_pool
) )

View File

@@ -13,6 +13,10 @@ class AgentNodeData(BaseNodeData):
agent_strategy_name: str agent_strategy_name: str
agent_strategy_label: str # redundancy agent_strategy_label: str # redundancy
memory: MemoryConfig | None = None memory: MemoryConfig | None = None
# The version of the tool parameter.
# If this value is None, it indicates this is a previous version
# and requires using the legacy parameter parsing rules.
tool_node_version: str | None = None
class AgentInput(BaseModel): class AgentInput(BaseModel):
value: Union[list[str], list[ToolSelector], Any] value: Union[list[str], list[ToolSelector], Any]

View File

@@ -73,6 +73,9 @@ NODE_TYPE_CLASSES_MAPPING: Mapping[NodeType, Mapping[str, type[BaseNode]]] = {
}, },
NodeType.TOOL: { NodeType.TOOL: {
LATEST_VERSION: ToolNode, LATEST_VERSION: ToolNode,
# This is an issue that caused problems before.
# Logically, we shouldn't use two different versions to point to the same class here,
# but in order to maintain compatibility with historical data, this approach has been retained.
"2": ToolNode, "2": ToolNode,
"1": ToolNode, "1": ToolNode,
}, },
@@ -123,6 +126,9 @@ NODE_TYPE_CLASSES_MAPPING: Mapping[NodeType, Mapping[str, type[BaseNode]]] = {
}, },
NodeType.AGENT: { NodeType.AGENT: {
LATEST_VERSION: AgentNode, LATEST_VERSION: AgentNode,
# This is an issue that caused problems before.
# Logically, we shouldn't use two different versions to point to the same class here,
# but in order to maintain compatibility with historical data, this approach has been retained.
"2": AgentNode, "2": AgentNode,
"1": AgentNode, "1": AgentNode,
}, },

View File

@@ -59,6 +59,10 @@ class ToolNodeData(BaseNodeData, ToolEntity):
return typ return typ
tool_parameters: dict[str, ToolInput] tool_parameters: dict[str, ToolInput]
# The version of the tool parameter.
# If this value is None, it indicates this is a previous version
# and requires using the legacy parameter parsing rules.
tool_node_version: str | None = None
@field_validator("tool_parameters", mode="before") @field_validator("tool_parameters", mode="before")
@classmethod @classmethod

View File

@@ -70,7 +70,13 @@ class ToolNode(BaseNode):
try: try:
from core.tools.tool_manager import ToolManager from core.tools.tool_manager import ToolManager
variable_pool = self.graph_runtime_state.variable_pool if self._node_data.version != "1" else None # This is an issue that caused problems before.
# Logically, we shouldn't use the node_data.version field for judgment
# But for backward compatibility with historical data
# this version field judgment is still preserved here.
variable_pool: VariablePool | None = None
if node_data.version != "1" or node_data.tool_node_version != "1":
variable_pool = self.graph_runtime_state.variable_pool
tool_runtime = ToolManager.get_workflow_tool_runtime( tool_runtime = ToolManager.get_workflow_tool_runtime(
self.tenant_id, self.app_id, self.node_id, self._node_data, self.invoke_from, variable_pool self.tenant_id, self.app_id, self.node_id, self._node_data, self.invoke_from, variable_pool
) )

View File

@@ -117,7 +117,7 @@ const Question: FC<QuestionProps> = ({
</div> </div>
<div <div
ref={contentRef} ref={contentRef}
className='bg-background-gradient-bg-fill-chat-bubble-bg-3 w-full rounded-2xl px-4 py-3 text-sm text-text-primary' className='w-full rounded-2xl bg-background-gradient-bg-fill-chat-bubble-bg-3 px-4 py-3 text-sm text-text-primary'
style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}} style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}}
> >
{ {

View File

@@ -7,7 +7,7 @@ import { renderI18nObject } from '@/i18n'
const nodeDefault: NodeDefault<AgentNodeType> = { const nodeDefault: NodeDefault<AgentNodeType> = {
defaultValue: { defaultValue: {
version: '2', tool_node_version: '2',
}, },
getAvailablePrevNodes(isChatMode) { getAvailablePrevNodes(isChatMode) {
return isChatMode return isChatMode
@@ -62,27 +62,29 @@ const nodeDefault: NodeDefault<AgentNodeType> = {
const userSettings = toolValue.settings const userSettings = toolValue.settings
const reasoningConfig = toolValue.parameters const reasoningConfig = toolValue.parameters
const version = payload.version const version = payload.version
const toolNodeVersion = payload.tool_node_version
const mergeVersion = version || toolNodeVersion
schemas.forEach((schema: any) => { schemas.forEach((schema: any) => {
if (schema?.required) { if (schema?.required) {
if (schema.form === 'form' && !version && !userSettings[schema.name]?.value) { if (schema.form === 'form' && !mergeVersion && !userSettings[schema.name]?.value) {
return { return {
isValid: false, isValid: false,
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }), errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
} }
} }
if (schema.form === 'form' && version && !userSettings[schema.name]?.value.value) { if (schema.form === 'form' && mergeVersion && !userSettings[schema.name]?.value.value) {
return { return {
isValid: false, isValid: false,
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }), errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
} }
} }
if (schema.form === 'llm' && !version && reasoningConfig[schema.name].auto === 0 && !reasoningConfig[schema.name]?.value) { if (schema.form === 'llm' && !mergeVersion && reasoningConfig[schema.name].auto === 0 && !reasoningConfig[schema.name]?.value) {
return { return {
isValid: false, isValid: false,
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }), errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
} }
} }
if (schema.form === 'llm' && version && reasoningConfig[schema.name].auto === 0 && !reasoningConfig[schema.name]?.value.value) { if (schema.form === 'llm' && mergeVersion && reasoningConfig[schema.name].auto === 0 && !reasoningConfig[schema.name]?.value.value) {
return { return {
isValid: false, isValid: false,
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }), errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),

View File

@@ -12,6 +12,7 @@ export type AgentNodeType = CommonNodeType & {
plugin_unique_identifier?: string plugin_unique_identifier?: string
memory?: Memory memory?: Memory
version?: string version?: string
tool_node_version?: string
} }
export enum AgentFeature { export enum AgentFeature {

View File

@@ -129,7 +129,7 @@ const useConfig = (id: string, payload: AgentNodeType) => {
} }
const formattingLegacyData = () => { const formattingLegacyData = () => {
if (inputs.version) if (inputs.version || inputs.tool_node_version)
return inputs return inputs
const newData = produce(inputs, (draft) => { const newData = produce(inputs, (draft) => {
const schemas = currentStrategy?.parameters || [] const schemas = currentStrategy?.parameters || []
@@ -140,7 +140,7 @@ const useConfig = (id: string, payload: AgentNodeType) => {
if (targetSchema?.type === FormTypeEnum.multiToolSelector) if (targetSchema?.type === FormTypeEnum.multiToolSelector)
draft.agent_parameters![key].value = draft.agent_parameters![key].value.map((tool: any) => formattingToolData(tool)) draft.agent_parameters![key].value = draft.agent_parameters![key].value.map((tool: any) => formattingToolData(tool))
}) })
draft.version = '2' draft.tool_node_version = '2'
}) })
return newData return newData
} }

View File

@@ -10,7 +10,7 @@ const nodeDefault: NodeDefault<ToolNodeType> = {
defaultValue: { defaultValue: {
tool_parameters: {}, tool_parameters: {},
tool_configurations: {}, tool_configurations: {},
version: '2', tool_node_version: '2',
}, },
getAvailablePrevNodes(isChatMode: boolean) { getAvailablePrevNodes(isChatMode: boolean) {
const nodes = isChatMode const nodes = isChatMode

View File

@@ -23,4 +23,5 @@ export type ToolNodeType = CommonNodeType & {
output_schema: Record<string, any> output_schema: Record<string, any>
paramSchemas?: Record<string, any>[] paramSchemas?: Record<string, any>[]
version?: string version?: string
tool_node_version?: string
} }

View File

@@ -286,8 +286,8 @@ export const initialNodes = (originNodes: Node[], originEdges: Edge[]) => {
} }
} }
if (node.data.type === BlockEnum.Tool && !(node as Node<ToolNodeType>).data.version) { if (node.data.type === BlockEnum.Tool && !(node as Node<ToolNodeType>).data.version && !(node as Node<ToolNodeType>).data.tool_node_version) {
(node as Node<ToolNodeType>).data.version = '2' (node as Node<ToolNodeType>).data.tool_node_version = '2'
const toolConfigurations = (node as Node<ToolNodeType>).data.tool_configurations const toolConfigurations = (node as Node<ToolNodeType>).data.tool_configurations
if (toolConfigurations && Object.keys(toolConfigurations).length > 0) { if (toolConfigurations && Object.keys(toolConfigurations).length > 0) {