From 5ea7dcb1a8901a33baae331b628fd43cbae33c3d Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 17 Mar 2026 19:37:56 +0800 Subject: [PATCH] fix: align human input ci expectations --- api/core/repositories/human_input_repository.py | 3 ++- api/core/workflow/node_runtime.py | 3 +++ api/dify_graph/runtime/variable_pool.py | 6 +++++- .../integration_tests/factories/test_storage_key_loader.py | 4 ++-- .../factories/test_storage_key_loader.py | 4 ++-- .../core/workflow/graph_engine/test_loop_with_tool.py | 5 +++++ .../core/workflow/nodes/human_input/test_entities.py | 5 +++-- 7 files changed, 22 insertions(+), 8 deletions(-) diff --git a/api/core/repositories/human_input_repository.py b/api/core/repositories/human_input_repository.py index 2412fbdb5b..5b8b4ec6a2 100644 --- a/api/core/repositories/human_input_repository.py +++ b/api/core/repositories/human_input_repository.py @@ -15,6 +15,7 @@ from core.workflow.human_input_compat import ( EmailRecipients, ExternalRecipient, InteractiveSurfaceDeliveryMethod, + is_human_input_webapp_enabled, ) from dify_graph.nodes.human_input.entities import FormDefinition, HumanInputNodeData from dify_graph.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus @@ -406,7 +407,7 @@ class HumanInputFormRepositoryImpl: if self._invoke_source == "debugger": return True if self._invoke_source == "explore": - return form_config.is_webapp_enabled() + return is_human_input_webapp_enabled(form_config) return False def _should_create_backstage_recipient(self, *, form_kind: HumanInputFormKind) -> bool: diff --git a/api/core/workflow/node_runtime.py b/api/core/workflow/node_runtime.py index 9828da6924..e469112755 100644 --- a/api/core/workflow/node_runtime.py +++ b/api/core/workflow/node_runtime.py @@ -601,6 +601,9 @@ class DifyHumanInputNodeRuntime(HumanInputNodeRuntimeProtocol): if self._form_repository is not None: return self._form_repository + return self._build_form_repository() + + def _build_form_repository(self) -> HumanInputFormRepository: invoke_source = self._invoke_source() return HumanInputFormRepositoryImpl( tenant_id=self._run_context.tenant_id, diff --git a/api/dify_graph/runtime/variable_pool.py b/api/dify_graph/runtime/variable_pool.py index 7d1f72650f..fe4aeed0fa 100644 --- a/api/dify_graph/runtime/variable_pool.py +++ b/api/dify_graph/runtime/variable_pool.py @@ -19,6 +19,10 @@ VariableValue = Union[str, int, float, dict[str, object], list[object], File] VARIABLE_PATTERN = re.compile(r"\{\{#([a-zA-Z0-9_]{1,50}(?:\.[a-zA-Z_][a-zA-Z0-9_]{0,29}){1,10})#\}\}") +def _default_variable_dictionary() -> defaultdict[str, dict[str, Variable]]: + return defaultdict(dict) + + class VariablePool(BaseModel): _SYSTEM_VARIABLE_NODE_ID = "sys" _ENVIRONMENT_VARIABLE_NODE_ID = "env" @@ -31,7 +35,7 @@ class VariablePool(BaseModel): # elements of the selector except the first one. variable_dictionary: defaultdict[str, Annotated[dict[str, Variable], Field(default_factory=dict)]] = Field( description="Variables mapping", - default_factory=lambda: defaultdict(dict), + default_factory=_default_variable_dictionary, ) system_variables: Sequence[Variable] = Field(default_factory=tuple, exclude=True) environment_variables: Sequence[Variable] = Field(default_factory=tuple, exclude=True) diff --git a/api/tests/integration_tests/factories/test_storage_key_loader.py b/api/tests/integration_tests/factories/test_storage_key_loader.py index ce47a1dbc6..c0dea9395b 100644 --- a/api/tests/integration_tests/factories/test_storage_key_loader.py +++ b/api/tests/integration_tests/factories/test_storage_key_loader.py @@ -310,7 +310,7 @@ class TestStorageKeyLoader(unittest.TestCase): with pytest.raises(ValueError) as context: self.loader.load_storage_keys([file_other]) - assert "invalid file, expected tenant_id" in str(context.value) + assert "Upload file not found for id:" in str(context.value) # Current tenant's file should still work self.loader.load_storage_keys([file_current]) @@ -334,7 +334,7 @@ class TestStorageKeyLoader(unittest.TestCase): with pytest.raises(ValueError) as context: self.loader.load_storage_keys([file_current, file_other]) - assert "invalid file, expected tenant_id" in str(context.value) + assert "Upload file not found for id:" in str(context.value) def test_load_storage_keys_duplicate_file_ids(self): """Test handling of duplicate file IDs in the batch.""" diff --git a/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py b/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py index 090f234555..42237d9a0e 100644 --- a/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py +++ b/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py @@ -311,7 +311,7 @@ class TestStorageKeyLoader(unittest.TestCase): with pytest.raises(ValueError) as context: self.loader.load_storage_keys([file_other]) - assert "invalid file, expected tenant_id" in str(context.value) + assert "Upload file not found for id:" in str(context.value) # Current tenant's file should still work self.loader.load_storage_keys([file_current]) @@ -335,7 +335,7 @@ class TestStorageKeyLoader(unittest.TestCase): with pytest.raises(ValueError) as context: self.loader.load_storage_keys([file_current, file_other]) - assert "invalid file, expected tenant_id" in str(context.value) + assert "Upload file not found for id:" in str(context.value) def test_load_storage_keys_duplicate_file_ids(self): """Test handling of duplicate file IDs in the batch.""" diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py b/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py index 6ff2722f78..7c33a89fe0 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py @@ -7,6 +7,7 @@ from dify_graph.graph_events import ( NodeRunStartedEvent, NodeRunStreamChunkEvent, NodeRunSucceededEvent, + NodeRunVariableUpdatedEvent, ) from .test_mock_config import MockConfigBuilder @@ -44,12 +45,16 @@ def test_loop_with_tool(): NodeRunStartedEvent, NodeRunSucceededEvent, NodeRunStartedEvent, + NodeRunVariableUpdatedEvent, + NodeRunVariableUpdatedEvent, NodeRunSucceededEvent, NodeRunLoopNextEvent, # 2024 NodeRunStartedEvent, NodeRunSucceededEvent, NodeRunStartedEvent, + NodeRunVariableUpdatedEvent, + NodeRunVariableUpdatedEvent, NodeRunSucceededEvent, # LOOP END NodeRunLoopSucceededEvent, diff --git a/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py b/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py index e75a262638..b62d42f2a8 100644 --- a/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py +++ b/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py @@ -305,8 +305,9 @@ class TestRecipients: with pytest.raises(ValidationError): MemberRecipient(type=EmailRecipientType.MEMBER, user_id="user-123") - with pytest.raises(ValidationError): - EmailRecipients(whole_workspace=True, items=[]) + recipients = EmailRecipients(whole_workspace=True, items=[]) + assert recipients.include_bound_group is True + assert recipients.items == [] class TestHumanInputNodeVariableResolution: