diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/core/workflow/nodes/agent/agent_node.py index c1b423d69d..9a8c289e47 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/core/workflow/nodes/agent/agent_node.py @@ -9,6 +9,7 @@ from dify_graph.node_events import NodeEventBase, NodeRunResult, StreamCompleted from dify_graph.nodes.base.node import Node from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from .clarification_helper import should_enable_clarification from .entities import AgentNodeData from .exceptions import ( AgentInvocationError, @@ -150,6 +151,11 @@ class AgentNode(Node[AgentNodeData]): node_id=self._node_id, node_execution_id=self.id, ) + # Extensibility hook for human clarification (HITL support) + # Currently a no-op, but allows future HITL implementation + if should_enable_clarification(self.node_data): + # Placeholder for future clarification logic + pass except PluginDaemonClientSideError as e: transform_error = AgentMessageTransformError( f"Failed to transform agent message: {str(e)}", original_error=e diff --git a/api/core/workflow/nodes/agent/clarification_helper.py b/api/core/workflow/nodes/agent/clarification_helper.py new file mode 100644 index 0000000000..90c1c313fb --- /dev/null +++ b/api/core/workflow/nodes/agent/clarification_helper.py @@ -0,0 +1,51 @@ +""" +Clarification helper for agent node human-in-the-loop support. + +This module provides extensibility hooks for future HITL (Human-In-The-Loop) features. +Currently, it serves as a placeholder for clarification request extraction and handling. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from .entities import AgentNodeData + + +def should_enable_clarification(node_data: AgentNodeData) -> bool: + """ + Check if human clarification is enabled for this agent node. + + Args: + node_data: The agent node data configuration. + + Returns: + True if human clarification is enabled, False otherwise. + """ + return node_data.enable_human_clarification + + +def extract_clarification_request( + agent_output: dict[str, Any], + enable_clarification: bool, +) -> dict[str, Any] | None: + """ + Extract clarification request from agent output if enabled. + + This is a placeholder for future HITL implementation. + Currently returns None as clarification is not yet implemented. + + Args: + agent_output: The output from agent execution. + enable_clarification: Whether clarification is enabled. + + Returns: + Clarification request dict if found and enabled, None otherwise. + """ + if not enable_clarification: + return None + + # Placeholder for future clarification extraction logic + # This will be extended when HITL feature is fully implemented + return None diff --git a/api/core/workflow/nodes/agent/entities.py b/api/core/workflow/nodes/agent/entities.py index 59842862ef..612b8df5f9 100644 --- a/api/core/workflow/nodes/agent/entities.py +++ b/api/core/workflow/nodes/agent/entities.py @@ -19,6 +19,8 @@ class AgentNodeData(BaseNodeData): # 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 + # Enable human clarification for agent reasoning + enable_human_clarification: bool = False class AgentInput(BaseModel): value: Union[list[str], list[ToolSelector], Any] diff --git a/api/tests/unit_tests/core/workflow/nodes/agent/test_clarification_helper.py b/api/tests/unit_tests/core/workflow/nodes/agent/test_clarification_helper.py new file mode 100644 index 0000000000..ee3bc304cc --- /dev/null +++ b/api/tests/unit_tests/core/workflow/nodes/agent/test_clarification_helper.py @@ -0,0 +1,95 @@ +""" +Tests for agent node clarification helper and configuration. +""" + +import pytest + +from core.workflow.nodes.agent.clarification_helper import ( + extract_clarification_request, + should_enable_clarification, +) +from core.workflow.nodes.agent.entities import AgentNodeData +from dify_graph.enums import NodeType + + +class TestClarificationHelper: + """Test suite for clarification helper functions.""" + + def test_should_enable_clarification_when_enabled(self): + """Test that should_enable_clarification returns True when enabled.""" + node_data = AgentNodeData( + id="test_node", + type=NodeType.AGENT, + agent_strategy_provider_name="test_provider", + agent_strategy_name="test_strategy", + agent_strategy_label="Test Strategy", + agent_parameters={}, + enable_human_clarification=True, + ) + assert should_enable_clarification(node_data) is True + + def test_should_enable_clarification_when_disabled(self): + """Test that should_enable_clarification returns False when disabled.""" + node_data = AgentNodeData( + id="test_node", + type=NodeType.AGENT, + agent_strategy_provider_name="test_provider", + agent_strategy_name="test_strategy", + agent_strategy_label="Test Strategy", + agent_parameters={}, + enable_human_clarification=False, + ) + assert should_enable_clarification(node_data) is False + + def test_should_enable_clarification_default_false(self): + """Test that clarification is disabled by default.""" + node_data = AgentNodeData( + id="test_node", + type=NodeType.AGENT, + agent_strategy_provider_name="test_provider", + agent_strategy_name="test_strategy", + agent_strategy_label="Test Strategy", + agent_parameters={}, + ) + assert should_enable_clarification(node_data) is False + + def test_extract_clarification_request_when_disabled(self): + """Test that extract_clarification_request returns None when disabled.""" + result = extract_clarification_request( + agent_output={"text": "test output"}, + enable_clarification=False, + ) + assert result is None + + def test_extract_clarification_request_when_enabled(self): + """Test that extract_clarification_request returns None when enabled (placeholder).""" + # Currently returns None as placeholder for future implementation + result = extract_clarification_request( + agent_output={"text": "test output"}, + enable_clarification=True, + ) + assert result is None + + def test_agent_node_data_with_clarification_field(self): + """Test that AgentNodeData properly stores enable_human_clarification.""" + node_data = AgentNodeData( + id="test_node", + type=NodeType.AGENT, + agent_strategy_provider_name="test_provider", + agent_strategy_name="test_strategy", + agent_strategy_label="Test Strategy", + agent_parameters={}, + enable_human_clarification=True, + ) + assert node_data.enable_human_clarification is True + + node_data_disabled = AgentNodeData( + id="test_node", + type=NodeType.AGENT, + agent_strategy_provider_name="test_provider", + agent_strategy_name="test_strategy", + agent_strategy_label="Test Strategy", + agent_parameters={}, + enable_human_clarification=False, + ) + assert node_data_disabled.enable_human_clarification is False diff --git a/web/app/components/workflow/nodes/agent/panel.tsx b/web/app/components/workflow/nodes/agent/panel.tsx index 14232bc639..4b006f4823 100644 --- a/web/app/components/workflow/nodes/agent/panel.tsx +++ b/web/app/components/workflow/nodes/agent/panel.tsx @@ -10,6 +10,7 @@ import { isSupportMCP } from '@/utils/plugin-version-feature' import { useStore } from '../../store' import { AgentStrategy } from '../_base/components/agent-strategy' import Field from '../_base/components/field' +import FormInputBoolean from '../_base/components/form-input-boolean' import { MCPToolAvailabilityProvider } from '../_base/components/mcp-tool-availability' import MemoryConfig from '../_base/components/memory-config' import OutputVars, { VarItem } from '../_base/components/output-vars' @@ -101,6 +102,22 @@ const AgentPanel: FC> = (props) => { /> )} + + + { + setInputs({ + ...inputs, + enable_human_clarification: value, + }) + }} + /> +
diff --git a/web/app/components/workflow/nodes/agent/types.ts b/web/app/components/workflow/nodes/agent/types.ts index efc7c0cd9a..280beb9507 100644 --- a/web/app/components/workflow/nodes/agent/types.ts +++ b/web/app/components/workflow/nodes/agent/types.ts @@ -13,6 +13,7 @@ export type AgentNodeType = CommonNodeType & { memory?: Memory version?: string tool_node_version?: string + enable_human_clarification?: boolean } export enum AgentFeature { diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json index 4d9f5adbac..56534dc295 100644 --- a/web/i18n/en-US/workflow.json +++ b/web/i18n/en-US/workflow.json @@ -373,6 +373,8 @@ "nodes.agent.toolbox": "toolbox", "nodes.agent.tools": "Tools", "nodes.agent.unsupportedStrategy": "Unsupported strategy", + "nodes.agent.enableHumanClarification.label": "Enable Human Clarification", + "nodes.agent.enableHumanClarification.tooltip": "Allow human intervention to clarify agent reasoning during execution", "nodes.answer.answer": "Answer", "nodes.answer.outputVars": "Output Variables", "nodes.assigner.append": "Append",