From b4e2af96e2c1318e2d7b389abdc1596f9ef273e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:17:04 +0800 Subject: [PATCH 1/3] chore(deps): bump @lexical/utils from 0.38.2 to 0.39.0 in /web (#31503) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package.json | 2 +- web/pnpm-lock.yaml | 80 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/web/package.json b/web/package.json index 69cc08bd32..48a6795d83 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 c98b57ee48..d5a8b529ad 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) @@ -2066,6 +2066,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==} @@ -2081,6 +2084,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==} @@ -2090,12 +2096,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==} @@ -2123,15 +2135,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: @@ -2619,6 +2640,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: @@ -6223,6 +6247,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'} @@ -10373,6 +10400,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 @@ -10401,6 +10436,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 @@ -10419,6 +10460,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 @@ -10432,6 +10479,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 @@ -10501,6 +10555,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 @@ -10508,6 +10566,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 @@ -10519,6 +10584,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 @@ -10973,6 +11045,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 @@ -15090,6 +15164,8 @@ snapshots: lexical@0.38.2: {} + lexical@0.39.0: {} + lib0@0.2.117: dependencies: isomorphic.js: 0.2.5 From b9f1d65d4fb601bf5b80eb9bb7df9e11b38fcc95 Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Mon, 26 Jan 2026 11:23:38 +0900 Subject: [PATCH 2/3] refactor: example of refine dict / Mapping (#31498) --- api/controllers/console/app/workflow.py | 6 ++++-- api/core/app/apps/advanced_chat/app_generator.py | 13 +++++++++---- api/core/app/apps/workflow/app_generator.py | 13 +++++++++---- api/services/app_generate_service.py | 11 +++++++++-- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/api/controllers/console/app/workflow.py b/api/controllers/console/app/workflow.py index b4f2ef0ba8..acaf85a6b1 100644 --- a/api/controllers/console/app/workflow.py +++ b/api/controllers/console/app/workflow.py @@ -470,7 +470,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( @@ -508,7 +508,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( @@ -999,6 +999,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( @@ -1147,6 +1148,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 feb0d3358c..528c45f6c8 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 @@ -304,7 +309,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]: """ @@ -320,7 +325,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 @@ -338,7 +343,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 2be773f103..ee205ed153 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 @@ -40,6 +42,9 @@ from models import Account, App, EndUser, Workflow, WorkflowNodeExecutionTrigger from models.enums import WorkflowRunTriggeredFrom 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__) @@ -381,7 +386,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]: """ @@ -397,7 +402,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 @@ -413,7 +418,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( From 7c12e923b6cd5e7e082241e2add8266b426b56d4 Mon Sep 17 00:00:00 2001 From: zyssyz123 <916125788@qq.com> Date: Mon, 26 Jan 2026 11:52:05 +0800 Subject: [PATCH 3/3] feat: add trial model list in system features (#31313) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: hj24 --- api/enums/hosted_provider.py | 21 +++++++++++++++++++++ api/services/feature_service.py | 14 ++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 api/enums/hosted_provider.py diff --git a/api/enums/hosted_provider.py b/api/enums/hosted_provider.py new file mode 100644 index 0000000000..c6d3715dc1 --- /dev/null +++ b/api/enums/hosted_provider.py @@ -0,0 +1,21 @@ +from enum import StrEnum + + +class HostedTrialProvider(StrEnum): + """ + Enum representing hosted model provider names for trial access. + """ + + OPENAI = "langgenius/openai/openai" + ANTHROPIC = "langgenius/anthropic/anthropic" + GEMINI = "langgenius/gemini/google" + X = "langgenius/x/x" + DEEPSEEK = "langgenius/deepseek/deepseek" + TONGYI = "langgenius/tongyi/tongyi" + + @property + def config_key(self) -> str: + """Return the config key used in dify_config (e.g., HOSTED_{config_key}_PAID_ENABLED).""" + if self == HostedTrialProvider.X: + return "XAI" + return self.name diff --git a/api/services/feature_service.py b/api/services/feature_service.py index b2fb3784e8..d94ae49d91 100644 --- a/api/services/feature_service.py +++ b/api/services/feature_service.py @@ -4,6 +4,7 @@ from pydantic import BaseModel, ConfigDict, Field from configs import dify_config from enums.cloud_plan import CloudPlan +from enums.hosted_provider import HostedTrialProvider from services.billing_service import BillingService from services.enterprise.enterprise_service import EnterpriseService @@ -170,6 +171,7 @@ class SystemFeatureModel(BaseModel): plugin_installation_permission: PluginInstallationPermissionModel = PluginInstallationPermissionModel() enable_change_email: bool = True plugin_manager: PluginManagerModel = PluginManagerModel() + trial_models: list[str] = [] enable_trial_app: bool = False enable_explore_banner: bool = False @@ -227,9 +229,21 @@ class FeatureService: system_features.is_allow_register = dify_config.ALLOW_REGISTER system_features.is_allow_create_workspace = dify_config.ALLOW_CREATE_WORKSPACE system_features.is_email_setup = dify_config.MAIL_TYPE is not None and dify_config.MAIL_TYPE != "" + system_features.trial_models = cls._fulfill_trial_models_from_env() system_features.enable_trial_app = dify_config.ENABLE_TRIAL_APP system_features.enable_explore_banner = dify_config.ENABLE_EXPLORE_BANNER + @classmethod + def _fulfill_trial_models_from_env(cls) -> list[str]: + return [ + provider.value + for provider in HostedTrialProvider + if ( + getattr(dify_config, f"HOSTED_{provider.config_key}_PAID_ENABLED", False) + and getattr(dify_config, f"HOSTED_{provider.config_key}_TRIAL_ENABLED", False) + ) + ] + @classmethod def _fulfill_params_from_env(cls, features: FeatureModel): features.can_replace_logo = dify_config.CAN_REPLACE_LOGO