Skip to content

feat(workflow): execute workflow tools as nested containers - #42820

Merged
MRZHUH merged 16 commits into
mainfrom
laipz8200/graphon-workflow-tool-execution
Oct 21, 2026
Merged

MRZHUH merged 16 commits into
mainfrom
laipz8200/graphon-workflow-tool-execution

Conversation

@laipz8200

@laipz8200 laipz8200 commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Summary

Run called Workflow Tools as child graphs under the same engine, so nested execution can pause, resume, stop, and preserve file output types. Materialize the referenced source graphs and tool definitions before execution; republishing a tool does not change an in-flight run, including calls inside loops and iterations.

The application service owns source loading and persistence. Store each child execution's caller workflow and node execution IDs explicitly, and save unfinished child records in batches when a run ends. Legacy entrypoints reject nested human-input workflows before execution begins.

Keep nested unfinished nodes durable before publishing a pause. SQL, Celery, and LogStore batch writers preserve a committed stop when queued node updates arrive later. The caller-locator migration follows the workflow task-control migration from the foundation PR.

Pin the API to 4fa22141774dff80e90e4dfa98ea3e6fbf0421bb, the Graphon 0.8.0 backport of langgenius/graphon#344, until a published release includes the fix. This keeps declared empty file-array types through container completion and saved runtime state. Convert typed node values to their public JSON shape before queuing Celery history writes, and retain the existing streamed text output. The standalone dify-agent dependency is unchanged. Nested workflow usage and step totals can be approximate, particularly when runs pause or stop; this remains an accepted known issue. Dify consumes the engine totals without adding a separate accounting implementation.

Depends on #42819. Source trace access and presentation are reviewed in the following PRs; the stack ultimately targets main.

@github-actions github-actions Bot added web This relates to changes on the web. size:XXL This PR changes 1000+ lines, ignoring generated files. labels Sep 23, 2026
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-10-20 16:12:13.776321771 +0000
+++ /tmp/pyrefly_pr.txt	2026-10-20 16:12:03.272248730 +0000
@@ -1069,103 +1069,101 @@
 ERROR `None` is not subscriptable [unsupported-operation]
    --> tests/test_containers_integration_tests/services/tools/test_tools_transform_service.py:805:16
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:109:38
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:108:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:113:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:112:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:188:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:187:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:208:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:207:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:223:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:222:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:257:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:256:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:273:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:272:27
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:290:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:289:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:323:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:322:27
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:340:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:339:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:369:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:368:27
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:395:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:394:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:425:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:424:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:442:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:441:27
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:459:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:458:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:494:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:493:27
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:510:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:509:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:553:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:545:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:567:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:558:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:599:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:591:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:613:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:605:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:631:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:623:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:632:30
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:624:30
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:685:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:670:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:697:51
-ERROR Object of class `NoneType` has no attribute `name` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:703:25
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:682:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:720:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:703:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:721:34
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:704:30
 ERROR Object of class `NoneType` has no attribute `name` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:732:16
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:714:16
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:760:27
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:742:27
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:777:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:759:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:807:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:789:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:821:51
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:803:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:830:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:812:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:831:30
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:813:30
 ERROR Object of class `NoneType` has no attribute `name` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:844:16
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:826:16
 ERROR Object of class `NoneType` has no attribute `updated_at` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:845:16
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:827:16
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:909:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:891:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:987:23
+   --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:969:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1031:27
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1013:27
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1048:51
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1030:51
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1072:23
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1054:23
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1083:54
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1065:54
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1088:77
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1070:77
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1105:83
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1087:83
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1119:80
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1101:80
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1131:79
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1113:79
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1143:78
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1125:78
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1156:23
+    --> tests/test_containers_integration_tests/services/tools/test_workflow_tools_manage_service.py:1138:23
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:107:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
@@ -2943,61 +2941,71 @@
 ERROR Argument `SimpleNamespace` is not assignable to parameter `node` with type `Node[Unknown]` in function `core.app.workflow.layers.observability.ObservabilityLayer.node_run_context` [bad-argument-type]
   --> tests/unit_tests/core/app/workflow/test_observability_layer_extra.py:50:37
 ERROR Argument `_RepoRecorder | Unknown` is not assignable to parameter `workflow_execution_repository` with type `WorkflowExecutionRepository` in function `services.workflow_persistence.WorkflowPersistenceLayer.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:109:39
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:142:39
 ERROR Argument `_RepoRecorder | Unknown` is not assignable to parameter `workflow_node_execution_repository` with type `WorkflowNodeExecutionRepository` in function `services.workflow_persistence.WorkflowPersistenceLayer.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:110:44
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:143:44
 ERROR Argument `object | None` is not assignable to parameter `trace_manager` with type `TraceQueueManager | None` in function `services.workflow_persistence.WorkflowPersistenceLayer.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:111:23
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:144:23
 ERROR Argument `None` is not assignable to parameter `command_channel` with type `CommandChannel` in function `graphon.engine.layer.base.Layer.initialize` [bad-argument-type]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:113:55
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:146:55
+ERROR Object of class `object` has no attribute `process_data` [missing-attribute]
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:200:16
+ERROR Object of class `object` has no attribute `metadata` [missing-attribute]
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:201:16
+ERROR `Literal['loop_id']` is not assignable to dict key type `WorkflowNodeExecutionMetadataKey` [bad-assignment]
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:243:90
+ERROR `None` is not subscriptable [unsupported-operation]
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:634:20
 ERROR Object of class `object` has no attribute `status` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:221:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:743:16
 ERROR Object of class `object` has no attribute `total_tokens` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:222:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:744:16
 ERROR Object of class `object` has no attribute `total_steps` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:223:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:745:16
 ERROR `SimpleNamespace` is not assignable to attribute `_graph_execution` with type `GraphExecution` [bad-assignment]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:233:42
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:755:42
 ERROR Object of class `object` has no attribute `status` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:238:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:760:16
 ERROR Object of class `object` has no attribute `exceptions_count` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:239:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:761:16
 ERROR Object of class `object` has no attribute `total_tokens` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:240:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:762:16
 ERROR Object of class `object` has no attribute `status` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:263:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:785:16
 ERROR Object of class `object` has no attribute `status` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:330:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:852:16
 ERROR Object of class `object` has no attribute `error_message` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:331:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:853:16
 ERROR Object of class `object` has no attribute `created_at` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:349:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:871:16
 ERROR Object of class `object` has no attribute `id` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:378:17
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:900:17
 ERROR Object of class `object` has no attribute `status` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:430:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:952:16
 ERROR Object of class `object` has no attribute `process_data` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:431:16
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:953:16
 ERROR Object of class `object` has no attribute `process_data` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:432:25
+   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:954:25
 ERROR Object of class `object` has no attribute `status` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:492:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1014:16
 ERROR Object of class `object` has no attribute `error` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:493:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1015:16
 ERROR Object of class `object` has no attribute `finished_at` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:494:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1016:16
 ERROR Object of class `object` has no attribute `process_data` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:496:20
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1018:20
 ERROR Object of class `object` has no attribute `process_data` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:497:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1019:16
 ERROR Object of class `object` has no attribute `status` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:524:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1046:16
 ERROR Object of class `object` has no attribute `finished_at` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:525:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1047:16
 ERROR Object of class `object` has no attribute `process_data` [missing-attribute]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:526:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1048:16
+ERROR `None` is not subscriptable [unsupported-operation]
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1123:16
 ERROR `None` is not subscriptable [unsupported-operation]
-   --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:598:16
+    --> tests/unit_tests/core/app/workflow/test_persistence_layer.py:1124:16
 ERROR Argument `None` is not assignable to parameter `app_id` with type `str` in function `core.callback_handler.index_tool_callback_handler.DatasetIndexToolCallbackHandler.__init__` [bad-argument-type]
    --> tests/unit_tests/core/callback_handler/test_index_tool_callback_handler.py:159:20
 ERROR Argument `None` is not assignable to parameter `message_id` with type `str` in function `core.callback_handler.index_tool_callback_handler.DatasetIndexToolCallbackHandler.__init__` [bad-argument-type]
@@ -3709,27 +3717,27 @@
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `json_object` [missing-attribute]
    --> tests/unit_tests/core/tools/utils/test_tool_engine_serialization.py:434:44
 ERROR Argument `list[FromClause]` is not assignable to parameter `tables` with type `Sequence[Table] | None` in function `sqlalchemy.sql.schema.MetaData.create_all` [bad-argument-type]
-  --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:77:56
+  --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:78:56
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `variable_name` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:539:22
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:565:22
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `variable_value` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:539:49
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:565:49
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `text` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:547:23
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:573:23
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `json_object` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:552:12
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:578:12
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `text` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:589:12
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:615:12
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `json_object` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:594:12
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:620:12
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `variable_name` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:615:12
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:641:12
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `variable_value` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:616:12
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:642:12
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `stream` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:617:12
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:643:12
 ERROR Object of type `ToolInvokeMessage.BlobChunkMessage | ToolInvokeMessage.BlobMessage | ToolInvokeMessage.FileMessage | ToolInvokeMessage.JsonMessage | ToolInvokeMessage.LogMessage | ToolInvokeMessage.RetrieverResourceMessage | ToolInvokeMessage.TextMessage | ToolInvokeMessage.VariableMessage | None` has no attribute `file_marker` [missing-attribute]
-   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:628:12
+   --> tests/unit_tests/core/tools/workflow_as_tool/test_tool.py:654:12
 ERROR Object of class `IExecutionContext` has no attribute `context_vars` [missing-attribute]
    --> tests/unit_tests/core/workflow/context/test_execution_context.py:320:16
 ERROR Object of class `BaseModel` has no attribute `base_url` [missing-attribute]
@@ -3781,11 +3789,11 @@
 ERROR Class member `EndBarrier.on_end` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
    --> tests/unit_tests/core/workflow/graph_engine/layers/test_observability.py:369:17
 ERROR Cannot extend final class `DifyNodeFactory` [invalid-inheritance]
-  --> tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py:37:23
+  --> tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py:38:23
 ERROR Class member `MockNodeFactory.create_node` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-  --> tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py:86:9
+   --> tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py:104:9
 ERROR Cannot set item in `dict[str, type[MockAgentNode] | type[MockCodeNode] | type[MockDocumentExtractorNode] | type[MockHttpRequestNode] | type[MockIterationNode] | type[MockKnowledgeRetrievalNode] | type[MockLLMNode] | type[MockLoopNode] | type[MockParameterExtractorNode] | type[MockQuestionClassifierNode] | type[MockTemplateTransformNode] | type[MockToolNode]]` [unsupported-operation]
-   --> tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py:169:44
+   --> tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py:187:44
 ERROR Unexpected keyword argument `node_id` in function `object.__init__` [unexpected-keyword]
    --> tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py:112:13
 ERROR Unexpected keyword argument `data` in function `object.__init__` [unexpected-keyword]
@@ -3883,51 +3891,51 @@
 ERROR `graph_runtime_state` is uninitialized [unbound-name]
    --> tests/unit_tests/core/workflow/graph_engine/test_table_runner.py:391:37
 ERROR Class member `FakeBindingResolver.resolve` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:145:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:154:9
 ERROR Class member `ExplodingSessionStore.save_active_snapshot` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:208:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:217:9
 ERROR Class member `FileOutputBackendClient._events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:227:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:236:9
 ERROR Class member `PlainTextOutputBackendClient._events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:247:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:256:9
 ERROR Class member `AgentMessageDeltaBackendClient._events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:265:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:274:9
 ERROR Class member `FailingStreamBackendClient.stream_events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:294:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:303:9
 ERROR Class member `FailingStreamBackendClient.cancel_run` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:305:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:314:9
 ERROR Class member `FailingStreamBackendClient.cancel_run_and_wait` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:309:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:318:9
 ERROR Class member `FailingAfterStartedStreamBackendClient.stream_events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:321:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:330:9
 ERROR Class member `TerminalWithoutSnapshotBackendClient._events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:338:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:347:9
 ERROR Class member `EmptyStreamBackendClient.stream_events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:355:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:364:9
 ERROR Class member `GenericFailingStreamBackendClient.stream_events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:368:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:377:9
 ERROR Class member `CancelFailingStreamBackendClient.cancel_run` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:381:9
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:390:9
 ERROR Argument `dict[str, str]` is not assignable to parameter `node_data` with type `DifyAgentNodeData` in function `core.workflow.nodes.agent_v2.agent_node.DifyAgentNode._extract_variable_selector_to_variable_mapping` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:482:19
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:493:19
 ERROR Class member `_UnavailableParticipantStore.load_existing_node_execution_scope` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:601:13
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:648:13
 ERROR Class member `_FailingSessionStore.load_or_create_node_execution_session` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:870:13
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:917:13
 ERROR Attribute `graph_execution` of class `RuntimeState` is a read-only property and cannot be set [read-only]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:948:5
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:995:5
 ERROR Object of class `NodeEventPayload` has no attribute `node_run_result` [missing-attribute]
-    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1019:14
+    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1066:14
 ERROR Class member `RetryingBackendClient._events` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1076:13
+    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1123:13
 ERROR `dict[str, int | str] | dict[str, str]` is not assignable to attribute `output_payload` with type `dict[str, object]` [bad-assignment]
-    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1077:35
+    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1124:35
 ERROR Object of class `NodeEventPayload` has no attribute `node_run_result` [missing-attribute]
-    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1097:14
+    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1144:14
 ERROR Object of class `NodeEventPayload` has no attribute `node_run_result` [missing-attribute]
-    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1142:14
+    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1189:14
 ERROR Argument `dict[str, dict[str, list[dict[str, str]] | Unknown]]` is not assignable to parameter `node_data` with type `DifyAgentNodeData` in function `core.workflow.nodes.agent_v2.agent_node.DifyAgentNode._extract_variable_selector_to_variable_mapping` [bad-argument-type]
-    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1165:19
+    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_agent_node.py:1212:19
 ERROR Object of class `Executable` has no attribute `compile` [missing-attribute]
    --> tests/unit_tests/core/workflow/nodes/agent_v2/test_binding_resolver.py:447:26
 ERROR Object of class `Executable` has no attribute `compile` [missing-attribute]
@@ -4307,11 +4315,11 @@
 ERROR Cannot index into `object` [bad-index]
     --> tests/unit_tests/core/workflow/nodes/agent_v2/test_runtime_request_builder.py:1701:14
 ERROR `not in` is not supported between `Literal['agent_workspace_binding_id']` and `None` [not-iterable]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_session_store.py:329:12
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_session_store.py:470:12
 ERROR Argument `dict[str, str]` is not assignable to parameter `process_data` with type `dict[str, object] | None` in function `_execution_row` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_session_store.py:353:69
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_session_store.py:494:69
 ERROR `not in` is not supported between `Literal['agent_workspace_binding_id']` and `None` [not-iterable]
-   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_session_store.py:362:12
+   --> tests/unit_tests/core/workflow/nodes/agent_v2/test_session_store.py:503:12
 ERROR Class member `_Version1.init_node_data` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
   --> tests/unit_tests/core/workflow/nodes/base/test_get_node_type_classes_mapping.py:40:13
 ERROR Class member `_Version1._get_error_strategy` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
@@ -4643,95 +4651,97 @@
 ERROR `SimpleNamespace` is not assignable to attribute `_dify_context` with type `DifyRunContext` [bad-assignment]
    --> tests/unit_tests/core/workflow/test_node_factory.py:409:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `node_data` with type `LLMNodeData | ParameterExtractorNodeData | QuestionClassifierNodeData` in function `core.workflow.node_factory.DifyNodeFactory._wrap_model_instance_for_node` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_factory.py:863:23
+   --> tests/unit_tests/core/workflow/test_node_factory.py:864:23
 ERROR Argument `_ModelInstanceStub` is not assignable to parameter `model_instance` with type `ModelInstance` in function `core.workflow.node_factory.DifyNodeFactory._wrap_model_instance_for_node` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_factory.py:864:28
+   --> tests/unit_tests/core/workflow/test_node_factory.py:865:28
 ERROR `SimpleNamespace` is not assignable to attribute `runtime_state` with type `RuntimeState` [bad-assignment]
-    --> tests/unit_tests/core/workflow/test_node_factory.py:1119:33
+    --> tests/unit_tests/core/workflow/test_node_factory.py:1120:33
 ERROR `SimpleNamespace` is not assignable to attribute `_dify_context` with type `DifyRunContext` [bad-assignment]
-    --> tests/unit_tests/core/workflow/test_node_factory.py:1249:33
-ERROR `SimpleNamespace` is not assignable to attribute `runtime_state` with type `RuntimeState` [bad-assignment]
     --> tests/unit_tests/core/workflow/test_node_factory.py:1250:33
+ERROR `SimpleNamespace` is not assignable to attribute `runtime_state` with type `RuntimeState` [bad-assignment]
+    --> tests/unit_tests/core/workflow/test_node_factory.py:1251:33
 ERROR Argument `list[FromClause]` is not assignable to parameter `tables` with type `Sequence[Table] | None` in function `sqlalchemy.sql.schema.MetaData.create_all` [bad-argument-type]
-  --> tests/unit_tests/core/workflow/test_node_runtime.py:64:56
+  --> tests/unit_tests/core/workflow/test_node_runtime.py:67:56
 ERROR `object | None` is not assignable to attribute `model_runtime` with type `LLMModelRuntime` [bad-assignment]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:127:30
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:130:30
 ERROR Object of class `ExternalRecipient` has no attribute `reference_id` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:201:12
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:204:12
 ERROR Argument `object` is not assignable to parameter `method` with type `EmailDeliveryMethod | InteractiveSurfaceDeliveryMethod` in function `core.workflow.node_runtime.apply_dify_debug_email_recipient` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:216:45
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:219:45
 ERROR Argument `_ModelInstanceStub` is not assignable to parameter `model_instance` with type `ModelInstance` in function `core.workflow.node_runtime.DifyPreparedLLM.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:239:32
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:242:32
 ERROR Object of class `FunctionType` has no attribute `assert_called_once_with` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:258:5
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:261:5
 ERROR Argument `_ModelInstanceStub` is not assignable to parameter `model_instance` with type `ModelInstance` in function `core.workflow.node_runtime.DifyPreparedLLM.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:272:32
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:275:32
 ERROR Argument `_ModelInstanceStub` is not assignable to parameter `model_instance` with type `ModelInstance` in function `core.workflow.node_runtime.DifyPreparedLLM.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:280:32
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:283:32
 ERROR Argument `SimpleNamespace` is not assignable to parameter `model_instance` with type `ModelInstance` in function `core.workflow.node_runtime.DifyPreparedLLM.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:307:32
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:310:32
 ERROR Argument `_ModelInstanceStub` is not assignable to parameter `model_instance` with type `ModelInstance` in function `core.workflow.node_runtime.DifyPreparedPollingLLM.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:332:39
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:335:39
 ERROR Object of class `FunctionType` has no attribute `return_value` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:397:5
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:400:5
 ERROR Object of class `FunctionType` has no attribute `side_effect` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:431:5
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:434:5
 ERROR Object of class `FunctionType` has no attribute `call_count` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:445:12
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:448:12
 ERROR Object of class `FunctionType` has no attribute `return_value` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:462:5
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:465:5
 ERROR Object of class `FunctionType` has no attribute `return_value` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:492:5
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:495:5
 ERROR Argument `_ModelInstanceStub` is not assignable to parameter `model_instance` with type `ModelInstance` in function `core.workflow.node_runtime.DifyPreparedPollingLLM.__init__` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:529:39
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:532:39
 ERROR Argument `Literal['chat']` is not assignable to parameter `model_mode` with type `LLMMode` in function `core.workflow.node_runtime.DifyPromptMessageSerializer.serialize` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:546:20
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:549:20
 ERROR Object of class `NoneType` has no attribute `storage_key` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:575:12
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:578:12
 ERROR Argument `object` is not assignable to parameter `variable_pool` with type `VariablePool | None` in function `core.workflow.node_runtime.DifyToolNodeRuntime.get_runtime` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:807:23
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:810:23
 ERROR Object of class `object` has no attribute `tool` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:811:12
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:814:12
 ERROR Object of class `object` has no attribute `parent_trace_context` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:812:12
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:815:12
 ERROR Object of class `object` has no attribute `trace_session_id` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:835:5
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:838:5
 ERROR Argument `object` is not assignable to parameter `variable_pool` with type `VariablePool | None` in function `core.workflow.node_runtime.DifyToolNodeRuntime.get_runtime` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:852:23
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:855:23
 ERROR Object of class `object` has no attribute `trace_session_id` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:856:12
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:859:12
 ERROR Argument `object` is not assignable to parameter `variable_pool` with type `VariablePool | None` in function `core.workflow.node_runtime.DifyToolNodeRuntime.get_runtime` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:884:23
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:887:23
 ERROR Object of class `object` has no attribute `tool` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_node_runtime.py:887:12
+   --> tests/unit_tests/core/workflow/test_node_runtime.py:890:12
+ERROR `in` is not supported between `Literal['Maximum execution steps exceeded: 3 > 2']` and `None` [not-iterable]
+  --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:92:16
 ERROR Class member `EmptySplitKey.split` overrides parent class `UserString` in an inconsistent manner [bad-override]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:636:17
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:659:17
 ERROR Class member `EmptySplitKey.split` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:636:17
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:659:17
 ERROR `TestMappingUserInputsBranches.test_rejects_invalid_node_variable_key.EmptySplitKey` is not assignable to dict key type `str` [bad-assignment]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:641:35
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:664:35
 ERROR Argument `TestWorkflowEntryNodeLayers.test_run_node_with_layers_reports_success.FakeNode` is not assignable to parameter `node` with type `Node[Unknown]` in function `core.workflow.workflow_entry.WorkflowEntry._run_node_with_layers` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:745:78
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:768:78
 ERROR Object of class `FunctionType` has no attribute `assert_called_once_with` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:750:13
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:773:13
 ERROR Object of class `FunctionType` has no attribute `assert_called_once_with` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:751:13
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:774:13
 ERROR Object of class `FunctionType` has no attribute `assert_called_once_with` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:752:13
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:775:13
 ERROR Object of class `FunctionType` has no attribute `assert_called_once_with` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:753:13
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:776:13
 ERROR Object of class `FunctionType` has no attribute `assert_called_once_with` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:754:13
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:777:13
 ERROR Argument `TestWorkflowEntryNodeLayers.test_run_node_with_layers_reports_errors.FakeNode` is not assignable to parameter `node` with type `Node[Unknown]` in function `core.workflow.workflow_entry.WorkflowEntry._run_node_with_layers` [bad-argument-type]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:781:73
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:804:73
 ERROR Object of class `FunctionType` has no attribute `call_args` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:784:20
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:807:20
 ERROR Object of class `FunctionType` has no attribute `call_args` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:785:31
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:808:31
 ERROR Object of class `FunctionType` has no attribute `call_args` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:786:20
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:809:20
 ERROR Object of class `FunctionType` has no attribute `call_args` [missing-attribute]
-   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:787:31
+   --> tests/unit_tests/core/workflow/test_workflow_entry_helpers.py:810:31
 ERROR Missing argument `case` in function `enterprise.telemetry.contracts.TelemetryEnvelope.__init__` [missing-argument]
    --> tests/unit_tests/enterprise/telemetry/test_contracts.py:110:30
 ERROR Missing argument `tenant_id` in function `enterprise.telemetry.contracts.TelemetryEnvelope.__init__` [missing-argument]
@@ -4752,10 +4762,26 @@
   --> tests/unit_tests/events/test_events_package_compat.py:28:5
 ERROR Object of class `Events` has no attribute `request_start` [missing-attribute]
   --> tests/unit_tests/events/test_events_package_compat.py:33:5
-ERROR Cannot instantiate `LogstoreAPIWorkflowNodeExecutionRepository` because the following members are abstract: `get_execution_snapshots_by_workflow_run`, `delete_expired_executions`, `count_by_runs`, `delete_by_runs`, `delete_executions_by_app`, `get_expired_executions_batch`, `delete_executions_by_ids`, `get_offloads_by_execution_ids` [bad-instantiation]
-  --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:18:64
-ERROR Cannot instantiate `LogstoreAPIWorkflowNodeExecutionRepository` because the following members are abstract: `get_execution_snapshots_by_workflow_run`, `delete_expired_executions`, `count_by_runs`, `delete_by_runs`, `delete_executions_by_app`, `get_expired_executions_batch`, `delete_executions_by_ids`, `get_offloads_by_execution_ids` [bad-instantiation]
-  --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:27:64
+ERROR Object of class `NoneType` has no attribute `partition` [missing-attribute]
+  --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:40:38
+ERROR `<=` is not supported between `None` and `int` [unsupported-operation]
+  --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:44:20
+ERROR Cannot instantiate `LogstoreAPIWorkflowNodeExecutionRepository` because the following members are abstract: `delete_expired_executions`, `count_by_runs`, `delete_by_runs`, `get_expired_executions_batch`, `delete_executions_by_ids`, `get_offloads_by_execution_ids` [bad-instantiation]
+  --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:49:64
+ERROR Cannot instantiate `LogstoreAPIWorkflowNodeExecutionRepository` because the following members are abstract: `delete_expired_executions`, `count_by_runs`, `delete_by_runs`, `get_expired_executions_batch`, `delete_executions_by_ids`, `get_offloads_by_execution_ids` [bad-instantiation]
+   --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:115:64
+ERROR Cannot instantiate `LogstoreAPIWorkflowNodeExecutionRepository` because the following members are abstract: `delete_expired_executions`, `count_by_runs`, `delete_by_runs`, `get_expired_executions_batch`, `delete_executions_by_ids`, `get_offloads_by_execution_ids` [bad-instantiation]
+   --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:131:64
+ERROR `None` is not assignable to dict value type `float | int | str` [bad-assignment]
+   --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:166:105
+ERROR Object of class `FunctionType` has no attribute `side_effect` [missing-attribute]
+   --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:180:9
+ERROR Object of class `FunctionType` has no attribute `call_count` [missing-attribute]
+   --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:202:12
+ERROR Object of class `FunctionType` has no attribute `call_args` [missing-attribute]
+   --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:203:13
+ERROR Cannot instantiate `LogstoreAPIWorkflowNodeExecutionRepository` because the following members are abstract: `delete_expired_executions`, `count_by_runs`, `delete_by_runs`, `get_expired_executions_batch`, `delete_executions_by_ids`, `get_offloads_by_execution_ids` [bad-instantiation]
+   --> tests/unit_tests/extensions/logstore/repositories/test_logstore_api_workflow_node_execution_repository.py:211:64
 ERROR Object of class `Span` has no attribute `events` [missing-attribute]
    --> tests/unit_tests/extensions/otel/test_retrieval_tracing.py:165:42
 ERROR Generator function should return `Generator` [bad-return]

@laipz8200
laipz8200 added this pull request to stack #42825 September 23, 2026 08:31
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Pyrefly Type Coverage

Metric Base PR Delta
Type coverage 76.28% 76.35% +0.06%
Strict coverage 75.96% 76.03% +0.07%
Typed symbols 64,406 64,744 +338
Untyped symbols 20,108 20,141 +33
Modules 3834 3850 +16

@laipz8200
laipz8200 removed this pull request from stack #42825 September 23, 2026 11:26
@laipz8200
laipz8200 added this pull request to stack #42841 September 23, 2026 11:26
@codecov

codecov Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.55581% with 56 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.85%. Comparing base (e7c2c6f) to head (e375a3d).

Files with missing lines Patch % Lines
...i/core/workflow/workflow_tool_container_handler.py 91.59% 11 Missing and 9 partials ⚠️
...s/sqlalchemy_workflow_node_execution_repository.py 85.71% 3 Missing and 3 partials ⚠️
api/tasks/workflow_node_execution_tasks.py 85.71% 3 Missing and 3 partials ⚠️
...sitories/api_workflow_node_execution_repository.py 83.87% 3 Missing and 2 partials ⚠️
api/core/workflow/node_execution_process_data.py 75.00% 2 Missing and 2 partials ⚠️
...ies/logstore_workflow_node_execution_repository.py 88.46% 2 Missing and 1 partial ⚠️
api/core/workflow/nodes/agent_v2/session_store.py 85.71% 1 Missing and 1 partial ⚠️
...logstore_api_workflow_node_execution_repository.py 96.36% 1 Missing and 1 partial ⚠️
...pi/repositories/workflow_tool_source_repository.py 93.10% 1 Missing and 1 partial ⚠️
...ories/celery_workflow_node_execution_repository.py 95.45% 0 Missing and 1 partial ⚠️
... and 5 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #42820      +/-   ##
==========================================
+ Coverage   88.80%   88.85%   +0.05%     
==========================================
  Files        5558     5565       +7     
  Lines      332910   333538     +628     
  Branches    66661    66739      +78     
==========================================
+ Hits       295644   296379     +735     
+ Misses      32088    31981     -107     
  Partials     5178     5178              
Flag Coverage Δ
api 88.94% <93.43%> (+0.08%) ⬆️
cli 94.01% <ø> (ø)
dify-ui 91.67% <ø> (ø)
web 88.46% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch from 15964dc to 9839886 Compare September 23, 2026 11:39
@ghfind-review ghfind-review Bot added the review: top ghfind author score; see https://ghfind.com label Sep 23, 2026
@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch from 9839886 to 5cb905c Compare September 23, 2026 12:25
@laipz8200
laipz8200 removed this pull request from stack #42841 September 23, 2026 12:42
@laipz8200
laipz8200 added this pull request to stack #42847 September 23, 2026 12:43
@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch from 5cb905c to d6021b7 Compare September 23, 2026 18:47
@laipz8200
laipz8200 requested a review from a team September 23, 2026 18:47
@laipz8200
laipz8200 removed this pull request from stack #42847 September 23, 2026 18:48
@laipz8200
laipz8200 added this pull request to stack #42853 September 23, 2026 18:48
@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch from d6021b7 to b052930 Compare September 23, 2026 18:53
@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch from 811ac44 to 4adeb7b Compare September 24, 2026 02:15
MRZHUH
MRZHUH previously approved these changes Sep 24, 2026
@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch from 8d5a2ba to 82705f0 Compare October 11, 2026 17:12
@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch 2 times, most recently from afbd172 to c43f2c0 Compare October 12, 2026 04:07
Comment thread api/services/workflow_run_agg.py
@laipz8200
laipz8200 force-pushed the laipz8200/graphon-workflow-tool-execution branch from 56d9d8c to ff4ed3e Compare October 14, 2026 00:00
41tair
41tair previously approved these changes Oct 20, 2026
WH-2099
WH-2099 previously approved these changes Oct 20, 2026

@WH-2099 WH-2099 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the nested Workflow Tool execution paths and fixed the two RAG pipeline regressions in d5b6d76.

Pipelines now reject unsupported Human Input before execution and mark an existing document as failed when tool validation fails.
Pipeline runs also use the existing Agent workspace retirement and collection flow.

Validation: 59 related tests passed, including debug/published execution, document failure handling, and nested Agent success/failure cleanup.
Ruff, targeted Pyrefly checks, and all 68 import contracts passed.
External Agent backend calls were mocked; CI for the new commit is still running.

WH-2099
WH-2099 previously approved these changes Oct 20, 2026

@WH-2099 WH-2099 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked the test correction in 6b7ef48.
The collection test now records calls directly while retaining the exact enqueue payload and workspace deletion assertions.

All 6 regression cases, Ruff, Pyrefly, and the test doubles guard against the PR base passed locally.
GitHub's Python Style check, including the previously failing guard, has now passed: https://github.com/langgenius/dify/actions/runs/39399948478/job/118551999000.
The remaining CI jobs are still running with no failures reported.

laipz8200 and others added 16 commits October 20, 2026 23:58
Materialize source graphs and tool definitions before execution. Preserve caller identity, typed outputs and nested pause or stop behavior while batching unfinished execution persistence in the upper service.
Preserve caller locators with direct model fields and narrow LogStore caller access to Dify node executions. Reuse existing truncation properties when retaining offloaded previews in SQL and Celery cleanup batches so persistence adds no dynamic attribute reads.
Remove synthetic Start-node usage and exact nested aggregate expectations from the human-input lifecycle test. Preserve pause, resume, stop, form identity, and output behavior coverage without introducing host-side accounting.
Replace spec mocks with real Graphon event streams, persisted human-input repositories, account sessions, and workflow tool instances. Preserve event delivery, retry history, payload, and pause/resume assertions under the upstream mock policy.
Use the existing call recorder for paused workflow tool results so the execution layer inherits the foundation mock-import cleanup while preserving the expected error and single generator invocation.
Tool persistence layers are created while the Engine runs, after node run
indices are bound and graph start has fired, so the fan-out to existing
tool layers never reached one. Drop it, inline the remaining helper, and
rely on save_many accepting an empty batch. The child variable pool starts
empty, so there is nothing to remove before the root inputs are added.

Drop the never-passed WorkflowEntry workflow_tool_sources parameter, inline
the single-use workspace key helper, and revert cosmetic rewrites of the
Celery and LogStore query hunks. Adapt the new tests to the trimmed
WorkflowEntry, _run_node_with_layers and WorkflowRunIndex signatures, and
restore the mock factory hook that DifyNodeFactory now defines.
Drop the upstream Human Input publication error declarations after nested workflow tools remove that restriction. Regenerate the console documentation and workspace contracts so the controller imports and advertised errors match supported behavior.
Extend the upstream storage cleanup to include nested workflow-tool executions owned by the deleted caller app. Reuse the trusted ownership predicate for selection, shared-file checks, and reference deletion while preserving foreign and orphan references and retry safety.
Exercise real workflow-tool runtimes, container frames, bindings, and LogStore protocol adapters. Keep external calls isolated and adapt all shared fixture callers to the validated runtime objects.
Apply durable cancellation to retry records in SQL and Celery batch writers. Exercise root and nested-source retries through actual engine event processing, preserving retry history, paused participants, and batched cleanup ownership.
Declare workflow-tool files as ArrayFileSegment and preserve the existing text stream with typed Graphon completion outputs. Pin only the API to the container-type patch on Graphon 0.8.0, and project runtime values before Celery payload serialization so history retains its public JSON shape. Cover snapshot restoration, parent variable types, async persistence, and existing file access behavior.
Chain batch workflow persistence retries to their original error and load Microsoft.PowerShell.Utility before the installer fixture constructs HttpResponseException.

Wait for the combobox popup to unmount before the Default story finishes, so accessibility checks observe the completed close transition.

Retain the typed file-access assertion and equal-length published snapshot fixtures required by the strict checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: top ghfind author score; see https://ghfind.com size:XXL This PR changes 1000+ lines, ignoring generated files. web This relates to changes on the web.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants