From 45164ce33e4608df77c7fb0ea8344bd45f9f48af Mon Sep 17 00:00:00 2001 From: 99 Date: Fri, 6 Feb 2026 10:37:26 +0800 Subject: [PATCH] refactor: strip external imports in workflow template transform (#32017) --- api/.importlinter | 1 - api/core/app/workflow/node_factory.py | 5 +++++ .../template_transform/template_transform_node.py | 13 +++++++++---- .../template_transform_node_spec.py | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/api/.importlinter b/api/.importlinter index 9dad254560..2a6bb66a95 100644 --- a/api/.importlinter +++ b/api/.importlinter @@ -136,7 +136,6 @@ ignore_imports = core.workflow.nodes.llm.llm_utils -> models.provider core.workflow.nodes.llm.llm_utils -> services.credit_pool_service core.workflow.nodes.llm.node -> core.tools.signature - core.workflow.nodes.template_transform.template_transform_node -> configs core.workflow.nodes.tool.tool_node -> core.callback_handler.workflow_tool_callback_handler core.workflow.nodes.tool.tool_node -> core.tools.tool_engine core.workflow.nodes.tool.tool_node -> core.tools.tool_manager diff --git a/api/core/app/workflow/node_factory.py b/api/core/app/workflow/node_factory.py index a5773bbef8..6717be3ae6 100644 --- a/api/core/app/workflow/node_factory.py +++ b/api/core/app/workflow/node_factory.py @@ -47,6 +47,7 @@ class DifyNodeFactory(NodeFactory): code_providers: Sequence[type[CodeNodeProvider]] | None = None, code_limits: CodeNodeLimits | None = None, template_renderer: Jinja2TemplateRenderer | None = None, + template_transform_max_output_length: int | None = None, http_request_http_client: HttpClientProtocol | None = None, http_request_tool_file_manager_factory: Callable[[], ToolFileManager] = ToolFileManager, http_request_file_manager: FileManagerProtocol | None = None, @@ -68,6 +69,9 @@ class DifyNodeFactory(NodeFactory): max_object_array_length=dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH, ) self._template_renderer = template_renderer or CodeExecutorJinja2TemplateRenderer() + self._template_transform_max_output_length = ( + template_transform_max_output_length or dify_config.TEMPLATE_TRANSFORM_MAX_LENGTH + ) self._http_request_http_client = http_request_http_client or ssrf_proxy self._http_request_tool_file_manager_factory = http_request_tool_file_manager_factory self._http_request_file_manager = http_request_file_manager or file_manager @@ -122,6 +126,7 @@ class DifyNodeFactory(NodeFactory): graph_init_params=self.graph_init_params, graph_runtime_state=self.graph_runtime_state, template_renderer=self._template_renderer, + max_output_length=self._template_transform_max_output_length, ) if node_type == NodeType.HTTP_REQUEST: diff --git a/api/core/workflow/nodes/template_transform/template_transform_node.py b/api/core/workflow/nodes/template_transform/template_transform_node.py index f7e0bccccf..3dc8afd9be 100644 --- a/api/core/workflow/nodes/template_transform/template_transform_node.py +++ b/api/core/workflow/nodes/template_transform/template_transform_node.py @@ -1,7 +1,6 @@ from collections.abc import Mapping, Sequence from typing import TYPE_CHECKING, Any -from configs import dify_config from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus from core.workflow.node_events import NodeRunResult from core.workflow.nodes.base.node import Node @@ -16,12 +15,13 @@ if TYPE_CHECKING: from core.workflow.entities import GraphInitParams from core.workflow.runtime import GraphRuntimeState -MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH = dify_config.TEMPLATE_TRANSFORM_MAX_LENGTH +DEFAULT_TEMPLATE_TRANSFORM_MAX_OUTPUT_LENGTH = 400_000 class TemplateTransformNode(Node[TemplateTransformNodeData]): node_type = NodeType.TEMPLATE_TRANSFORM _template_renderer: Jinja2TemplateRenderer + _max_output_length: int def __init__( self, @@ -31,6 +31,7 @@ class TemplateTransformNode(Node[TemplateTransformNodeData]): graph_runtime_state: "GraphRuntimeState", *, template_renderer: Jinja2TemplateRenderer | None = None, + max_output_length: int | None = None, ) -> None: super().__init__( id=id, @@ -40,6 +41,10 @@ class TemplateTransformNode(Node[TemplateTransformNodeData]): ) self._template_renderer = template_renderer or CodeExecutorJinja2TemplateRenderer() + if max_output_length is not None and max_output_length <= 0: + raise ValueError("max_output_length must be a positive integer") + self._max_output_length = max_output_length or DEFAULT_TEMPLATE_TRANSFORM_MAX_OUTPUT_LENGTH + @classmethod def get_default_config(cls, filters: Mapping[str, object] | None = None) -> Mapping[str, object]: """ @@ -69,11 +74,11 @@ class TemplateTransformNode(Node[TemplateTransformNodeData]): except TemplateRenderError as e: return NodeRunResult(inputs=variables, status=WorkflowNodeExecutionStatus.FAILED, error=str(e)) - if len(rendered) > MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH: + if len(rendered) > self._max_output_length: return NodeRunResult( inputs=variables, status=WorkflowNodeExecutionStatus.FAILED, - error=f"Output length exceeds {MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH} characters", + error=f"Output length exceeds {self._max_output_length} characters", ) return NodeRunResult( diff --git a/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py b/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py index 66d6c3c56b..61bdcbd250 100644 --- a/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py @@ -217,7 +217,6 @@ class TestTemplateTransformNode: @patch( "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template" ) - @patch("core.workflow.nodes.template_transform.template_transform_node.MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH", 10) def test_run_output_length_exceeds_limit( self, mock_execute, basic_node_data, mock_graph, mock_graph_runtime_state, graph_init_params ): @@ -231,6 +230,7 @@ class TestTemplateTransformNode: graph_init_params=graph_init_params, graph=mock_graph, graph_runtime_state=mock_graph_runtime_state, + max_output_length=10, ) result = node._run()