diff --git a/api/controllers/console/app/workflow.py b/api/controllers/console/app/workflow.py index 4e9722e0dc..de60e3b615 100644 --- a/api/controllers/console/app/workflow.py +++ b/api/controllers/console/app/workflow.py @@ -495,7 +495,7 @@ class AdvancedChatDraftRunLoopNodeApi(Resource): Run draft workflow loop node """ current_user, _ = current_account_with_tenant() - args = LoopNodeRunPayload.model_validate(console_ns.payload or {}).model_dump(exclude_none=True) + args = LoopNodeRunPayload.model_validate(console_ns.payload or {}) try: response = AppGenerateService.generate_single_loop( @@ -533,7 +533,7 @@ class WorkflowDraftRunLoopNodeApi(Resource): Run draft workflow loop node """ current_user, _ = current_account_with_tenant() - args = LoopNodeRunPayload.model_validate(console_ns.payload or {}).model_dump(exclude_none=True) + args = LoopNodeRunPayload.model_validate(console_ns.payload or {}) try: response = AppGenerateService.generate_single_loop( @@ -1050,6 +1050,7 @@ class DraftWorkflowTriggerRunApi(Resource): if not event: return jsonable_encoder({"status": "waiting", "retry_in": LISTENING_RETRY_IN}) workflow_args = dict(event.workflow_args) + workflow_args[SKIP_PREPARE_USER_INPUTS_KEY] = True return helper.compact_generate_response( AppGenerateService.generate( @@ -1198,6 +1199,7 @@ class DraftWorkflowTriggerRunAllApi(Resource): try: workflow_args = dict(trigger_debug_event.workflow_args) + workflow_args[SKIP_PREPARE_USER_INPUTS_KEY] = True response = AppGenerateService.generate( app_model=app_model, diff --git a/api/core/app/apps/advanced_chat/app_generator.py b/api/core/app/apps/advanced_chat/app_generator.py index ef15b18c76..34fbeb104c 100644 --- a/api/core/app/apps/advanced_chat/app_generator.py +++ b/api/core/app/apps/advanced_chat/app_generator.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import contextvars import logging import threading import uuid from collections.abc import Generator, Mapping -from typing import Any, Literal, Union, overload +from typing import TYPE_CHECKING, Any, Literal, Union, overload from flask import Flask, current_app from pydantic import ValidationError @@ -13,6 +15,9 @@ from sqlalchemy.orm import Session, sessionmaker import contexts from configs import dify_config from constants import UUID_NIL + +if TYPE_CHECKING: + from controllers.console.app.workflow import LoopNodeRunPayload from core.app.app_config.features.file_upload.manager import FileUploadConfigManager from core.app.apps.advanced_chat.app_config_manager import AdvancedChatAppConfigManager from core.app.apps.advanced_chat.app_runner import AdvancedChatAppRunner @@ -308,7 +313,7 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator): workflow: Workflow, node_id: str, user: Account | EndUser, - args: Mapping, + args: LoopNodeRunPayload, streaming: bool = True, ) -> Mapping[str, Any] | Generator[str | Mapping[str, Any], Any, None]: """ @@ -324,7 +329,7 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator): if not node_id: raise ValueError("node_id is required") - if args.get("inputs") is None: + if args.inputs is None: raise ValueError("inputs is required") # convert to app config @@ -342,7 +347,7 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator): stream=streaming, invoke_from=InvokeFrom.DEBUGGER, extras={"auto_generate_conversation_name": False}, - single_loop_run=AdvancedChatAppGenerateEntity.SingleLoopRunEntity(node_id=node_id, inputs=args["inputs"]), + single_loop_run=AdvancedChatAppGenerateEntity.SingleLoopRunEntity(node_id=node_id, inputs=args.inputs), ) contexts.plugin_tool_providers.set({}) contexts.plugin_tool_providers_lock.set(threading.Lock()) diff --git a/api/core/app/apps/workflow/app_generator.py b/api/core/app/apps/workflow/app_generator.py index f9199ceebb..2a7225fd4c 100644 --- a/api/core/app/apps/workflow/app_generator.py +++ b/api/core/app/apps/workflow/app_generator.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import contextvars import logging import threading import uuid from collections.abc import Generator, Mapping, Sequence -from typing import Any, Literal, Union, overload +from typing import TYPE_CHECKING, Any, Literal, Union, overload from flask import Flask, current_app from pydantic import ValidationError @@ -44,6 +46,9 @@ from models.workflow_features import WorkflowFeatures from services.sandbox.sandbox_provider_service import SandboxProviderService from services.workflow_draft_variable_service import DraftVarLoader, WorkflowDraftVariableService +if TYPE_CHECKING: + from controllers.console.app.workflow import LoopNodeRunPayload + SKIP_PREPARE_USER_INPUTS_KEY = "_skip_prepare_user_inputs" logger = logging.getLogger(__name__) @@ -385,7 +390,7 @@ class WorkflowAppGenerator(BaseAppGenerator): workflow: Workflow, node_id: str, user: Account | EndUser, - args: Mapping[str, Any], + args: LoopNodeRunPayload, streaming: bool = True, ) -> Mapping[str, Any] | Generator[str | Mapping[str, Any], None, None]: """ @@ -401,7 +406,7 @@ class WorkflowAppGenerator(BaseAppGenerator): if not node_id: raise ValueError("node_id is required") - if args.get("inputs") is None: + if args.inputs is None: raise ValueError("inputs is required") # convert to app config @@ -417,7 +422,7 @@ class WorkflowAppGenerator(BaseAppGenerator): stream=streaming, invoke_from=InvokeFrom.DEBUGGER, extras={"auto_generate_conversation_name": False}, - single_loop_run=WorkflowAppGenerateEntity.SingleLoopRunEntity(node_id=node_id, inputs=args["inputs"]), + single_loop_run=WorkflowAppGenerateEntity.SingleLoopRunEntity(node_id=node_id, inputs=args.inputs or {}), workflow_execution_id=str(uuid.uuid4()), ) contexts.plugin_tool_providers.set({}) diff --git a/api/services/app_generate_service.py b/api/services/app_generate_service.py index cc58899dc4..ce85f2e914 100644 --- a/api/services/app_generate_service.py +++ b/api/services/app_generate_service.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import uuid from collections.abc import Generator, Mapping -from typing import Any, Union +from typing import TYPE_CHECKING, Any, Union from configs import dify_config from core.app.apps.advanced_chat.app_generator import AdvancedChatAppGenerator @@ -18,6 +20,9 @@ from services.errors.app import QuotaExceededError, WorkflowIdFormatError, Workf from services.errors.llm import InvokeRateLimitError from services.workflow_service import WorkflowService +if TYPE_CHECKING: + from controllers.console.app.workflow import LoopNodeRunPayload + class AppGenerateService: @classmethod @@ -165,7 +170,9 @@ class AppGenerateService: raise ValueError(f"Invalid app mode {app_model.mode}") @classmethod - def generate_single_loop(cls, app_model: App, user: Account, node_id: str, args: Any, streaming: bool = True): + def generate_single_loop( + cls, app_model: App, user: Account, node_id: str, args: LoopNodeRunPayload, streaming: bool = True + ): if app_model.mode == AppMode.ADVANCED_CHAT: workflow = cls._get_workflow(app_model, InvokeFrom.DEBUGGER) return AdvancedChatAppGenerator.convert_to_event_stream( diff --git a/web/package.json b/web/package.json index 51abaddb23..7333a3766c 100644 --- a/web/package.json +++ b/web/package.json @@ -67,7 +67,7 @@ "@lexical/react": "0.38.2", "@lexical/selection": "0.38.2", "@lexical/text": "0.38.2", - "@lexical/utils": "0.38.2", + "@lexical/utils": "0.39.0", "@monaco-editor/react": "4.7.0", "@octokit/core": "6.1.6", "@octokit/request-error": "6.1.8", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 5e366a931d..edc733372a 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -94,8 +94,8 @@ importers: specifier: 0.38.2 version: 0.38.2 '@lexical/utils': - specifier: 0.38.2 - version: 0.38.2 + specifier: 0.39.0 + version: 0.39.0 '@monaco-editor/react': specifier: 4.7.0 version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -2081,6 +2081,9 @@ packages: '@lexical/clipboard@0.38.2': resolution: {integrity: sha512-dDShUplCu8/o6BB9ousr3uFZ9bltR+HtleF/Tl8FXFNPpZ4AXhbLKUoJuucRuIr+zqT7RxEv/3M6pk/HEoE6NQ==} + '@lexical/clipboard@0.39.0': + resolution: {integrity: sha512-ylrHy8M+I5EH4utwqivslugqQhvgLTz9VEJdrb2RjbhKQEXwMcqKCRWh6cRfkYx64onE2YQE0nRIdzHhExEpLQ==} + '@lexical/code@0.38.2': resolution: {integrity: sha512-wpqgbmPsfi/+8SYP0zI2kml09fGPRhzO5litR9DIbbSGvcbawMbRNcKLO81DaTbsJRnBJiQvbBBBJAwZKRqgBw==} @@ -2096,6 +2099,9 @@ packages: '@lexical/extension@0.38.2': resolution: {integrity: sha512-qbUNxEVjAC0kxp7hEMTzktj0/51SyJoIJWK6Gm790b4yNBq82fEPkksfuLkRg9VQUteD0RT1Nkjy8pho8nNamw==} + '@lexical/extension@0.39.0': + resolution: {integrity: sha512-mp/WcF8E53FWPiUHgHQz382J7u7C4+cELYNkC00dKaymf8NhS6M65Y8tyDikNGNUcLXSzaluwK0HkiKjTYGhVQ==} + '@lexical/hashtag@0.38.2': resolution: {integrity: sha512-jNI4Pv+plth39bjOeeQegMypkjDmoMWBMZtV0lCynBpkkPFlfMnyL9uzW/IxkZnX8LXWSw5mbWk07nqOUNTCrA==} @@ -2105,12 +2111,18 @@ packages: '@lexical/html@0.38.2': resolution: {integrity: sha512-pC5AV+07bmHistRwgG3NJzBMlIzSdxYO6rJU4eBNzyR4becdiLsI4iuv+aY7PhfSv+SCs7QJ9oc4i5caq48Pkg==} + '@lexical/html@0.39.0': + resolution: {integrity: sha512-7VLWP5DpzBg3kKctpNK6PbhymKAtU6NAnKieopCfCIWlMW+EqpldteiIXGqSqrMRK0JWTmF1gKgr9nnQyOOsXw==} + '@lexical/link@0.38.2': resolution: {integrity: sha512-UOKTyYqrdCR9+7GmH6ZVqJTmqYefKGMUHMGljyGks+OjOGZAQs78S1QgcPEqltDy+SSdPSYK7wAo6gjxZfEq9g==} '@lexical/list@0.38.2': resolution: {integrity: sha512-OQm9TzatlMrDZGxMxbozZEHzMJhKxAbH1TOnOGyFfzpfjbnFK2y8oLeVsfQZfZRmiqQS4Qc/rpFnRP2Ax5dsbA==} + '@lexical/list@0.39.0': + resolution: {integrity: sha512-mxgSxUrakTCHtC+gF30BChQBJTsCMiMgfC2H5VvhcFwXMgsKE/aK9+a+C/sSvvzCmPXqzYsuAcGkJcrY3e5xlw==} + '@lexical/mark@0.38.2': resolution: {integrity: sha512-U+8KGwc3cP5DxSs15HfkP2YZJDs5wMbWQAwpGqep9bKphgxUgjPViKhdi+PxIt2QEzk7WcoZWUsK1d2ty/vSmg==} @@ -2138,15 +2150,24 @@ packages: '@lexical/selection@0.38.2': resolution: {integrity: sha512-eMFiWlBH6bEX9U9sMJ6PXPxVXTrihQfFeiIlWLuTpEIDF2HRz7Uo1KFRC/yN6q0DQaj7d9NZYA6Mei5DoQuz5w==} + '@lexical/selection@0.39.0': + resolution: {integrity: sha512-j0cgNuTKDCdf/4MzRnAUwEqG6C/WQp18k2WKmX5KIVZJlhnGIJmlgSBrxjo8AuZ16DIHxTm2XNB4cUDCgZNuPA==} + '@lexical/table@0.38.2': resolution: {integrity: sha512-uu0i7yz0nbClmHOO5ZFsinRJE6vQnFz2YPblYHAlNigiBedhqMwSv5bedrzDq8nTTHwych3mC63tcyKIrM+I1g==} + '@lexical/table@0.39.0': + resolution: {integrity: sha512-1eH11kV4bJ0fufCYl8DpE19kHwqUI8Ev5CZwivfAtC3ntwyNkeEpjCc0pqeYYIWN/4rTZ5jgB3IJV4FntyfCzw==} + '@lexical/text@0.38.2': resolution: {integrity: sha512-+juZxUugtC4T37aE3P0l4I9tsWbogDUnTI/mgYk4Ht9g+gLJnhQkzSA8chIyfTxbj5i0A8yWrUUSw+/xA7lKUQ==} '@lexical/utils@0.38.2': resolution: {integrity: sha512-y+3rw15r4oAWIEXicUdNjfk8018dbKl7dWHqGHVEtqzAYefnEYdfD2FJ5KOTXfeoYfxi8yOW7FvzS4NZDi8Bfw==} + '@lexical/utils@0.39.0': + resolution: {integrity: sha512-8YChidpMJpwQc4nex29FKUeuZzC++QCS/Jt46lPuy1GS/BZQoPHFKQ5hyVvM9QVhc5CEs4WGNoaCZvZIVN8bQw==} + '@lexical/yjs@0.38.2': resolution: {integrity: sha512-fg6ZHNrVQmy1AAxaTs8HrFbeNTJCaCoEDPi6pqypHQU3QVfqr4nq0L0EcHU/TRlR1CeduEPvZZIjUUxWTZ0u8g==} peerDependencies: @@ -2634,6 +2655,9 @@ packages: '@preact/signals-core@1.12.1': resolution: {integrity: sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA==} + '@preact/signals-core@1.12.2': + resolution: {integrity: sha512-5Yf8h1Ke3SMHr15xl630KtwPTW4sYDFkkxS0vQ8UiQLWwZQnrF9IKaVG1mN5VcJz52EcWs2acsc/Npjha/7ysA==} + '@preact/signals@1.3.2': resolution: {integrity: sha512-naxcJgUJ6BTOROJ7C3QML7KvwKwCXQJYTc5L/b0eEsdYgPB6SxwoQ1vDGcS0Q7GVjAenVq/tXrybVdFShHYZWg==} peerDependencies: @@ -6269,6 +6293,9 @@ packages: lexical@0.38.2: resolution: {integrity: sha512-JJmfsG3c4gwBHzUGffbV7ifMNkKAWMCnYE3xJl87gty7hjyV5f3xq7eqTjP5HFYvO4XpjJvvWO2/djHp5S10tw==} + lexical@0.39.0: + resolution: {integrity: sha512-lpLv7MEJH5QDujEDlYqettL3ATVtNYjqyimzqgrm0RvCm3AO9WXSdsgTxuN7IAZRu88xkxCDeYubeUf4mNZVdg==} + lib0@0.2.117: resolution: {integrity: sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==} engines: {node: '>=16'} @@ -10479,6 +10506,14 @@ snapshots: '@lexical/utils': 0.38.2 lexical: 0.38.2 + '@lexical/clipboard@0.39.0': + dependencies: + '@lexical/html': 0.39.0 + '@lexical/list': 0.39.0 + '@lexical/selection': 0.39.0 + '@lexical/utils': 0.39.0 + lexical: 0.39.0 + '@lexical/code@0.38.2': dependencies: '@lexical/utils': 0.38.2 @@ -10507,6 +10542,12 @@ snapshots: '@preact/signals-core': 1.12.1 lexical: 0.38.2 + '@lexical/extension@0.39.0': + dependencies: + '@lexical/utils': 0.39.0 + '@preact/signals-core': 1.12.2 + lexical: 0.39.0 + '@lexical/hashtag@0.38.2': dependencies: '@lexical/text': 0.38.2 @@ -10525,6 +10566,12 @@ snapshots: '@lexical/utils': 0.38.2 lexical: 0.38.2 + '@lexical/html@0.39.0': + dependencies: + '@lexical/selection': 0.39.0 + '@lexical/utils': 0.39.0 + lexical: 0.39.0 + '@lexical/link@0.38.2': dependencies: '@lexical/extension': 0.38.2 @@ -10538,6 +10585,13 @@ snapshots: '@lexical/utils': 0.38.2 lexical: 0.38.2 + '@lexical/list@0.39.0': + dependencies: + '@lexical/extension': 0.39.0 + '@lexical/selection': 0.39.0 + '@lexical/utils': 0.39.0 + lexical: 0.39.0 + '@lexical/mark@0.38.2': dependencies: '@lexical/utils': 0.38.2 @@ -10607,6 +10661,10 @@ snapshots: dependencies: lexical: 0.38.2 + '@lexical/selection@0.39.0': + dependencies: + lexical: 0.39.0 + '@lexical/table@0.38.2': dependencies: '@lexical/clipboard': 0.38.2 @@ -10614,6 +10672,13 @@ snapshots: '@lexical/utils': 0.38.2 lexical: 0.38.2 + '@lexical/table@0.39.0': + dependencies: + '@lexical/clipboard': 0.39.0 + '@lexical/extension': 0.39.0 + '@lexical/utils': 0.39.0 + lexical: 0.39.0 + '@lexical/text@0.38.2': dependencies: lexical: 0.38.2 @@ -10625,6 +10690,13 @@ snapshots: '@lexical/table': 0.38.2 lexical: 0.38.2 + '@lexical/utils@0.39.0': + dependencies: + '@lexical/list': 0.39.0 + '@lexical/selection': 0.39.0 + '@lexical/table': 0.39.0 + lexical: 0.39.0 + '@lexical/yjs@0.38.2(yjs@13.6.27)': dependencies: '@lexical/offset': 0.38.2 @@ -11079,6 +11151,8 @@ snapshots: '@preact/signals-core@1.12.1': {} + '@preact/signals-core@1.12.2': {} + '@preact/signals@1.3.2(preact@10.28.0)': dependencies: '@preact/signals-core': 1.12.1 @@ -15228,6 +15302,8 @@ snapshots: lexical@0.38.2: {} + lexical@0.39.0: {} + lib0@0.2.117: dependencies: isomorphic.js: 0.2.5