mirror of
https://github.com/langgenius/dify.git
synced 2026-03-14 11:47:05 +00:00
Compare commits
6 Commits
main
...
move-trigg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a30a64d51b | ||
|
|
34ef10c818 | ||
|
|
26fedca865 | ||
|
|
2fd4e9e259 | ||
|
|
9e8a4c8a71 | ||
|
|
238497b7ab |
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
from enum import StrEnum
|
||||
|
||||
from flask_restx import Resource, marshal_with
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -10,7 +11,6 @@ from controllers.console.wraps import account_initialization_required, edit_perm
|
||||
from extensions.ext_database import db
|
||||
from fields.app_fields import app_server_fields
|
||||
from libs.login import current_account_with_tenant, login_required
|
||||
from models.enums import AppMCPServerStatus
|
||||
from models.model import AppMCPServer
|
||||
|
||||
DEFAULT_REF_TEMPLATE_SWAGGER_2_0 = "#/definitions/{model}"
|
||||
@@ -19,6 +19,11 @@ DEFAULT_REF_TEMPLATE_SWAGGER_2_0 = "#/definitions/{model}"
|
||||
app_server_model = console_ns.model("AppServer", app_server_fields)
|
||||
|
||||
|
||||
class AppMCPServerStatus(StrEnum):
|
||||
ACTIVE = "active"
|
||||
INACTIVE = "inactive"
|
||||
|
||||
|
||||
class MCPServerCreatePayload(BaseModel):
|
||||
description: str | None = Field(default=None, description="Server description")
|
||||
parameters: dict = Field(..., description="Server parameters configuration")
|
||||
@@ -112,10 +117,9 @@ class AppMCPServerController(Resource):
|
||||
|
||||
server.parameters = json.dumps(payload.parameters, ensure_ascii=False)
|
||||
if payload.status:
|
||||
try:
|
||||
server.status = AppMCPServerStatus(payload.status)
|
||||
except ValueError:
|
||||
if payload.status not in [status.value for status in AppMCPServerStatus]:
|
||||
raise ValueError("Invalid status")
|
||||
server.status = payload.status
|
||||
db.session.commit()
|
||||
return server
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ from libs.datetime_utils import naive_utc_now
|
||||
from libs.helper import EmailStr, TimestampField, extract_remote_ip, timezone
|
||||
from libs.login import current_account_with_tenant, login_required
|
||||
from models import AccountIntegrate, InvitationCode
|
||||
from models.account import AccountStatus, InvitationCodeStatus
|
||||
from models.account import AccountStatus
|
||||
from services.account_service import AccountService
|
||||
from services.billing_service import BillingService
|
||||
from services.errors.account import CurrentPasswordIncorrectError as ServiceCurrentPasswordIncorrectError
|
||||
@@ -216,7 +216,7 @@ class AccountInitApi(Resource):
|
||||
db.session.query(InvitationCode)
|
||||
.where(
|
||||
InvitationCode.code == args.invitation_code,
|
||||
InvitationCode.status == InvitationCodeStatus.UNUSED,
|
||||
InvitationCode.status == "unused",
|
||||
)
|
||||
.first()
|
||||
)
|
||||
@@ -224,7 +224,7 @@ class AccountInitApi(Resource):
|
||||
if not invitation_code:
|
||||
raise InvalidInvitationCodeError()
|
||||
|
||||
invitation_code.status = InvitationCodeStatus.USED
|
||||
invitation_code.status = "used"
|
||||
invitation_code.used_at = naive_utc_now()
|
||||
invitation_code.used_by_tenant_id = account.current_tenant_id
|
||||
invitation_code.used_by_account_id = account.id
|
||||
|
||||
@@ -6,13 +6,13 @@ from pydantic import BaseModel, Field, ValidationError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from controllers.common.schema import register_schema_model
|
||||
from controllers.console.app.mcp_server import AppMCPServerStatus
|
||||
from controllers.mcp import mcp_ns
|
||||
from core.mcp import types as mcp_types
|
||||
from core.mcp.server.streamable_http import handle_mcp_request
|
||||
from dify_graph.variables.input_entities import VariableEntity
|
||||
from extensions.ext_database import db
|
||||
from libs import helper
|
||||
from models.enums import AppMCPServerStatus
|
||||
from models.model import App, AppMCPServer, AppMode, EndUser
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ from core.app.entities.queue_entities import (
|
||||
QueueWorkflowSucceededEvent,
|
||||
)
|
||||
from core.workflow.node_factory import DifyNodeFactory
|
||||
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
|
||||
from core.workflow.workflow_entry import WorkflowEntry
|
||||
from dify_graph.entities import GraphInitParams
|
||||
from dify_graph.entities.graph_config import NodeConfigDictAdapter
|
||||
@@ -63,7 +64,6 @@ from dify_graph.graph_events import (
|
||||
NodeRunSucceededEvent,
|
||||
)
|
||||
from dify_graph.graph_events.graph import GraphRunAbortedEvent
|
||||
from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.runtime import GraphRuntimeState, VariablePool
|
||||
from dify_graph.system_variable import SystemVariable
|
||||
from dify_graph.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader, load_into_variable_pool
|
||||
|
||||
@@ -316,7 +316,7 @@ class QueueNodeStartedEvent(AppQueueEvent):
|
||||
start_at: datetime
|
||||
agent_strategy: AgentNodeStrategyInit | None = None
|
||||
|
||||
# FIXME(-LAN-): only for ToolNode, need to refactor
|
||||
# Legacy provider fields kept for existing start-event consumers.
|
||||
provider_type: str # should be a core.tools.entities.tool_entities.ToolProviderType
|
||||
provider_id: str
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ from core.trigger.debug.events import (
|
||||
build_plugin_pool_key,
|
||||
build_webhook_pool_key,
|
||||
)
|
||||
from core.workflow.nodes.trigger_plugin.entities import TriggerEventNodeData
|
||||
from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig
|
||||
from dify_graph.entities.graph_config import NodeConfigDict
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.nodes.trigger_plugin.entities import TriggerEventNodeData
|
||||
from dify_graph.nodes.trigger_schedule.entities import ScheduleConfig
|
||||
from extensions.ext_redis import redis_client
|
||||
from libs.datetime_utils import ensure_naive_utc, naive_utc_now
|
||||
from libs.schedule_utils import calculate_next_run_at
|
||||
|
||||
@@ -22,6 +22,7 @@ from core.rag.retrieval.dataset_retrieval import DatasetRetrieval
|
||||
from core.rag.summary_index.summary_index import SummaryIndex
|
||||
from core.repositories.human_input_repository import HumanInputFormRepositoryImpl
|
||||
from core.tools.tool_file_manager import ToolFileManager
|
||||
from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.entities.base_node_data import BaseNodeData
|
||||
from dify_graph.entities.graph_config import NodeConfigDict, NodeConfigDictAdapter
|
||||
from dify_graph.entities.graph_init_params import DIFY_RUN_CONTEXT_KEY
|
||||
@@ -39,7 +40,6 @@ from dify_graph.nodes.document_extractor import UnstructuredApiConfig
|
||||
from dify_graph.nodes.http_request import build_http_request_config
|
||||
from dify_graph.nodes.llm.entities import LLMNodeData
|
||||
from dify_graph.nodes.llm.exc import LLMModeRequiredError, ModelNotExistError
|
||||
from dify_graph.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.nodes.parameter_extractor.entities import ParameterExtractorNodeData
|
||||
from dify_graph.nodes.question_classifier.entities import QuestionClassifierNodeData
|
||||
from dify_graph.nodes.template_transform.template_renderer import (
|
||||
|
||||
1
api/core/workflow/nodes/__init__.py
Normal file
1
api/core/workflow/nodes/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Core-owned workflow node packages."""
|
||||
30
api/core/workflow/nodes/node_mapping.py
Normal file
30
api/core/workflow/nodes/node_mapping.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""Node mapping for workflow execution.
|
||||
|
||||
`core.workflow` owns the trigger node implementations, while the remaining node
|
||||
implementations still live under `dify_graph`. This module imports the
|
||||
core-owned node packages first, then asks the shared `Node` registry to load the
|
||||
rest of the workflow nodes from `dify_graph`.
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import pkgutil
|
||||
from collections.abc import Mapping
|
||||
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.nodes.base.node import Node
|
||||
|
||||
LATEST_VERSION = "latest"
|
||||
|
||||
|
||||
def _register_core_workflow_nodes() -> None:
|
||||
import core.workflow.nodes as workflow_nodes_pkg
|
||||
|
||||
for _, modname, _ in pkgutil.walk_packages(workflow_nodes_pkg.__path__, workflow_nodes_pkg.__name__ + "."):
|
||||
if modname == "core.workflow.nodes.node_mapping":
|
||||
continue
|
||||
importlib.import_module(modname)
|
||||
|
||||
|
||||
_register_core_workflow_nodes()
|
||||
|
||||
NODE_TYPE_CLASSES_MAPPING: Mapping[NodeType, Mapping[str, type[Node]]] = Node.get_node_type_classes_mapping()
|
||||
@@ -6,7 +6,8 @@ from pydantic import BaseModel, Field, ValidationInfo, field_validator
|
||||
from core.trigger.entities.entities import EventParameter
|
||||
from dify_graph.entities.base_node_data import BaseNodeData
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.nodes.trigger_plugin.exc import TriggerEventParameterError
|
||||
|
||||
from .exc import TriggerEventParameterError
|
||||
|
||||
|
||||
class TriggerEventNodeData(BaseNodeData):
|
||||
@@ -3,6 +3,7 @@ from collections.abc import Mapping
|
||||
from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID
|
||||
from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus
|
||||
from dify_graph.enums import NodeExecutionType, NodeType
|
||||
from dify_graph.graph_events import NodeRunStartedEvent
|
||||
from dify_graph.node_events import NodeRunResult
|
||||
from dify_graph.nodes.base.node import Node
|
||||
|
||||
@@ -32,6 +33,11 @@ class TriggerEventNode(Node[TriggerEventNodeData]):
|
||||
def version(cls) -> str:
|
||||
return "1"
|
||||
|
||||
def customize_start_event(self, event: NodeRunStartedEvent) -> None:
|
||||
provider_id = self.node_data.provider_id
|
||||
event.provider_id = provider_id
|
||||
event.extras["provider_id"] = provider_id
|
||||
|
||||
def _run(self) -> NodeRunResult:
|
||||
"""
|
||||
Run the plugin trigger node.
|
||||
3
api/core/workflow/nodes/trigger_schedule/__init__.py
Normal file
3
api/core/workflow/nodes/trigger_schedule/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .trigger_schedule_node import TriggerScheduleNode
|
||||
|
||||
__all__ = ["TriggerScheduleNode"]
|
||||
@@ -5,7 +5,8 @@ from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionSta
|
||||
from dify_graph.enums import NodeExecutionType, NodeType
|
||||
from dify_graph.node_events import NodeRunResult
|
||||
from dify_graph.nodes.base.node import Node
|
||||
from dify_graph.nodes.trigger_schedule.entities import TriggerScheduleNodeData
|
||||
|
||||
from .entities import TriggerScheduleNodeData
|
||||
|
||||
|
||||
class TriggerScheduleNode(Node[TriggerScheduleNodeData]):
|
||||
@@ -9,6 +9,7 @@ from core.app.entities.app_invoke_entities import InvokeFrom, UserFrom, build_di
|
||||
from core.app.workflow.layers.llm_quota import LLMQuotaLayer
|
||||
from core.app.workflow.layers.observability import ObservabilityLayer
|
||||
from core.workflow.node_factory import DifyNodeFactory
|
||||
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.constants import ENVIRONMENT_VARIABLE_NODE_ID
|
||||
from dify_graph.entities import GraphInitParams
|
||||
from dify_graph.entities.graph_config import NodeConfigDictAdapter
|
||||
@@ -23,7 +24,6 @@ from dify_graph.graph_engine.protocols.command_channel import CommandChannel
|
||||
from dify_graph.graph_events import GraphEngineEvent, GraphNodeEventBase, GraphRunFailedEvent
|
||||
from dify_graph.nodes import NodeType
|
||||
from dify_graph.nodes.base.node import Node
|
||||
from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.runtime import ChildGraphNotFoundError, GraphRuntimeState, VariablePool
|
||||
from dify_graph.system_variable import SystemVariable
|
||||
from dify_graph.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader, load_into_variable_pool
|
||||
|
||||
@@ -15,8 +15,9 @@ class NodeRunStartedEvent(GraphNodeEventBase):
|
||||
predecessor_node_id: str | None = None
|
||||
agent_strategy: AgentNodeStrategyInit | None = None
|
||||
start_at: datetime = Field(..., description="node start time")
|
||||
extras: dict[str, object] = Field(default_factory=dict)
|
||||
|
||||
# FIXME(-LAN-): only for ToolNode
|
||||
# Legacy provider fields kept for existing start-event consumers.
|
||||
provider_type: str = ""
|
||||
provider_id: str = ""
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ class Node(Generic[NodeDataT]):
|
||||
# Skip base class itself
|
||||
if cls is Node:
|
||||
return
|
||||
# Only register production node implementations defined under dify_graph.nodes.*
|
||||
# Only register production node implementations defined under dify_graph.nodes.*.
|
||||
# This prevents test helper subclasses from polluting the global registry and
|
||||
# accidentally overriding real node types (e.g., a test Answer node).
|
||||
module_name = getattr(cls, "__module__", "")
|
||||
@@ -273,6 +273,10 @@ class Node(Generic[NodeDataT]):
|
||||
"""Optional hook for subclasses requiring extra initialization."""
|
||||
return
|
||||
|
||||
def customize_start_event(self, event: NodeRunStartedEvent) -> None:
|
||||
"""Optional hook for subclasses to attach start-event metadata or extras."""
|
||||
return
|
||||
|
||||
@property
|
||||
def graph_init_params(self) -> GraphInitParams:
|
||||
return self._graph_init_params
|
||||
@@ -379,12 +383,6 @@ class Node(Generic[NodeDataT]):
|
||||
start_event.provider_id = f"{plugin_id}/{provider_name}"
|
||||
start_event.provider_type = getattr(self.node_data, "provider_type", "")
|
||||
|
||||
from dify_graph.nodes.trigger_plugin.trigger_event_node import TriggerEventNode
|
||||
|
||||
if isinstance(self, TriggerEventNode):
|
||||
start_event.provider_id = getattr(self.node_data, "provider_id", "")
|
||||
start_event.provider_type = getattr(self.node_data, "provider_type", "")
|
||||
|
||||
from dify_graph.nodes.agent.agent_node import AgentNode
|
||||
from dify_graph.nodes.agent.entities import AgentNodeData
|
||||
|
||||
@@ -394,6 +392,8 @@ class Node(Generic[NodeDataT]):
|
||||
icon=self.agent_strategy_icon,
|
||||
)
|
||||
|
||||
self.customize_start_event(start_event)
|
||||
|
||||
# ===
|
||||
yield start_event
|
||||
|
||||
@@ -524,6 +524,7 @@ class Node(Generic[NodeDataT]):
|
||||
"""Return mapping of NodeType -> {version -> Node subclass} using __init_subclass__ registry.
|
||||
|
||||
Import all modules under dify_graph.nodes so subclasses register themselves on import.
|
||||
Higher-level packages may register additional nodes before calling this helper.
|
||||
Then we return a readonly view of the registry to avoid accidental mutation.
|
||||
"""
|
||||
# Import all node modules to ensure they are loaded (thus registered)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
from dify_graph.nodes.trigger_schedule.trigger_schedule_node import TriggerScheduleNode
|
||||
|
||||
__all__ = ["TriggerScheduleNode"]
|
||||
@@ -4,7 +4,7 @@ from typing import cast
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from dify_graph.nodes.trigger_schedule.entities import SchedulePlanUpdate
|
||||
from core.workflow.nodes.trigger_schedule.entities import SchedulePlanUpdate
|
||||
from events.app_event import app_published_workflow_was_updated
|
||||
from extensions.ext_database import db
|
||||
from models import AppMode, Workflow, WorkflowSchedulePlan
|
||||
|
||||
@@ -323,11 +323,6 @@ class AccountIntegrate(TypeBase):
|
||||
)
|
||||
|
||||
|
||||
class InvitationCodeStatus(enum.StrEnum):
|
||||
UNUSED = "unused"
|
||||
USED = "used"
|
||||
|
||||
|
||||
class InvitationCode(TypeBase):
|
||||
__tablename__ = "invitation_codes"
|
||||
__table_args__ = (
|
||||
@@ -339,11 +334,7 @@ class InvitationCode(TypeBase):
|
||||
id: Mapped[int] = mapped_column(sa.Integer, init=False)
|
||||
batch: Mapped[str] = mapped_column(String(255))
|
||||
code: Mapped[str] = mapped_column(String(32))
|
||||
status: Mapped[InvitationCodeStatus] = mapped_column(
|
||||
EnumText(InvitationCodeStatus, length=16),
|
||||
server_default=sa.text("'unused'"),
|
||||
default=InvitationCodeStatus.UNUSED,
|
||||
)
|
||||
status: Mapped[str] = mapped_column(String(16), server_default=sa.text("'unused'"), default="unused")
|
||||
used_at: Mapped[datetime | None] = mapped_column(DateTime, default=None)
|
||||
used_by_tenant_id: Mapped[str | None] = mapped_column(StringUUID, default=None)
|
||||
used_by_account_id: Mapped[str | None] = mapped_column(StringUUID, default=None)
|
||||
@@ -375,13 +366,10 @@ class TenantPluginPermission(TypeBase):
|
||||
)
|
||||
tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
install_permission: Mapped[InstallPermission] = mapped_column(
|
||||
EnumText(InstallPermission, length=16),
|
||||
nullable=False,
|
||||
server_default="everyone",
|
||||
default=InstallPermission.EVERYONE,
|
||||
String(16), nullable=False, server_default="everyone", default=InstallPermission.EVERYONE
|
||||
)
|
||||
debug_permission: Mapped[DebugPermission] = mapped_column(
|
||||
EnumText(DebugPermission, length=16), nullable=False, server_default="noone", default=DebugPermission.NOBODY
|
||||
String(16), nullable=False, server_default="noone", default=DebugPermission.NOBODY
|
||||
)
|
||||
|
||||
|
||||
@@ -407,13 +395,10 @@ class TenantPluginAutoUpgradeStrategy(TypeBase):
|
||||
)
|
||||
tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
strategy_setting: Mapped[StrategySetting] = mapped_column(
|
||||
EnumText(StrategySetting, length=16),
|
||||
nullable=False,
|
||||
server_default="fix_only",
|
||||
default=StrategySetting.FIX_ONLY,
|
||||
String(16), nullable=False, server_default="fix_only", default=StrategySetting.FIX_ONLY
|
||||
)
|
||||
upgrade_mode: Mapped[UpgradeMode] = mapped_column(
|
||||
EnumText(UpgradeMode, length=16), nullable=False, server_default="exclude", default=UpgradeMode.EXCLUDE
|
||||
String(16), nullable=False, server_default="exclude", default=UpgradeMode.EXCLUDE
|
||||
)
|
||||
exclude_plugins: Mapped[list[str]] = mapped_column(sa.JSON, nullable=False, default_factory=list)
|
||||
include_plugins: Mapped[list[str]] = mapped_column(sa.JSON, nullable=False, default_factory=list)
|
||||
|
||||
@@ -72,23 +72,3 @@ class AppTriggerType(StrEnum):
|
||||
|
||||
# for backward compatibility
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
|
||||
class AppStatus(StrEnum):
|
||||
"""App Status Enum"""
|
||||
|
||||
NORMAL = "normal"
|
||||
|
||||
|
||||
class AppMCPServerStatus(StrEnum):
|
||||
"""AppMCPServer Status Enum"""
|
||||
|
||||
NORMAL = "normal"
|
||||
ACTIVE = "active"
|
||||
INACTIVE = "inactive"
|
||||
|
||||
|
||||
class ConversationStatus(StrEnum):
|
||||
"""Conversation Status Enum"""
|
||||
|
||||
NORMAL = "normal"
|
||||
|
||||
@@ -29,7 +29,7 @@ from libs.uuid_utils import uuidv7
|
||||
from .account import Account, Tenant
|
||||
from .base import Base, TypeBase, gen_uuidv4_string
|
||||
from .engine import db
|
||||
from .enums import AppMCPServerStatus, AppStatus, ConversationStatus, CreatorUserRole, MessageStatus
|
||||
from .enums import CreatorUserRole, MessageStatus
|
||||
from .provider_ids import GenericProviderID
|
||||
from .types import EnumText, LongText, StringUUID
|
||||
|
||||
@@ -343,9 +343,7 @@ class App(Base):
|
||||
icon_background: Mapped[str | None] = mapped_column(String(255))
|
||||
app_model_config_id = mapped_column(StringUUID, nullable=True)
|
||||
workflow_id = mapped_column(StringUUID, nullable=True)
|
||||
status: Mapped[AppStatus] = mapped_column(
|
||||
EnumText(AppStatus, length=255), server_default=sa.text("'normal'"), default=AppStatus.NORMAL
|
||||
)
|
||||
status: Mapped[str] = mapped_column(String(255), server_default=sa.text("'normal'"))
|
||||
enable_site: Mapped[bool] = mapped_column(sa.Boolean)
|
||||
enable_api: Mapped[bool] = mapped_column(sa.Boolean)
|
||||
api_rpm: Mapped[int] = mapped_column(sa.Integer, server_default=sa.text("0"))
|
||||
@@ -1009,9 +1007,7 @@ class Conversation(Base):
|
||||
introduction = mapped_column(LongText)
|
||||
system_instruction = mapped_column(LongText)
|
||||
system_instruction_tokens: Mapped[int] = mapped_column(sa.Integer, nullable=False, server_default=sa.text("0"))
|
||||
status: Mapped[ConversationStatus] = mapped_column(
|
||||
EnumText(ConversationStatus, length=255), nullable=False, default=ConversationStatus.NORMAL
|
||||
)
|
||||
status: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
|
||||
# The `invoke_from` records how the conversation is created.
|
||||
#
|
||||
@@ -1775,9 +1771,7 @@ class MessageFile(TypeBase):
|
||||
)
|
||||
message_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
type: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
transfer_method: Mapped[FileTransferMethod] = mapped_column(
|
||||
EnumText(FileTransferMethod, length=255), nullable=False
|
||||
)
|
||||
transfer_method: Mapped[FileTransferMethod] = mapped_column(String(255), nullable=False)
|
||||
created_by_role: Mapped[CreatorUserRole] = mapped_column(EnumText(CreatorUserRole, length=255), nullable=False)
|
||||
created_by: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
belongs_to: Mapped[Literal["user", "assistant"] | None] = mapped_column(String(255), nullable=True, default=None)
|
||||
@@ -1987,9 +1981,7 @@ class AppMCPServer(TypeBase):
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
description: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
server_code: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
status: Mapped[AppMCPServerStatus] = mapped_column(
|
||||
EnumText(AppMCPServerStatus, length=255), nullable=False, server_default=sa.text("'normal'")
|
||||
)
|
||||
status: Mapped[str] = mapped_column(String(255), nullable=False, server_default=sa.text("'normal'"))
|
||||
parameters: Mapped[str] = mapped_column(LongText, nullable=False)
|
||||
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
@@ -2043,9 +2035,7 @@ class Site(Base):
|
||||
customize_domain = mapped_column(String(255))
|
||||
customize_token_strategy: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
prompt_public: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, server_default=sa.text("false"))
|
||||
status: Mapped[AppStatus] = mapped_column(
|
||||
EnumText(AppStatus, length=255), nullable=False, server_default=sa.text("'normal'"), default=AppStatus.NORMAL
|
||||
)
|
||||
status = mapped_column(String(255), nullable=False, server_default=sa.text("'normal'"))
|
||||
created_by = mapped_column(StringUUID, nullable=True)
|
||||
created_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
updated_by = mapped_column(StringUUID, nullable=True)
|
||||
|
||||
@@ -20,6 +20,7 @@ from sqlalchemy.orm import Session
|
||||
from configs import dify_config
|
||||
from core.helper import ssrf_proxy
|
||||
from core.plugin.entities.plugin import PluginDependency
|
||||
from core.workflow.nodes.trigger_schedule.trigger_schedule_node import TriggerScheduleNode
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.model_runtime.utils.encoders import jsonable_encoder
|
||||
from dify_graph.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData
|
||||
@@ -27,7 +28,6 @@ from dify_graph.nodes.llm.entities import LLMNodeData
|
||||
from dify_graph.nodes.parameter_extractor.entities import ParameterExtractorNodeData
|
||||
from dify_graph.nodes.question_classifier.entities import QuestionClassifierNodeData
|
||||
from dify_graph.nodes.tool.entities import ToolNodeData
|
||||
from dify_graph.nodes.trigger_schedule.trigger_schedule_node import TriggerScheduleNode
|
||||
from events.app_event import app_model_config_was_updated, app_was_created
|
||||
from extensions.ext_redis import redis_client
|
||||
from factories import variable_factory
|
||||
|
||||
@@ -36,6 +36,7 @@ from core.rag.entities.event import (
|
||||
)
|
||||
from core.repositories.factory import DifyCoreRepositoryFactory
|
||||
from core.repositories.sqlalchemy_workflow_node_execution_repository import SQLAlchemyWorkflowNodeExecutionRepository
|
||||
from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
|
||||
from core.workflow.workflow_entry import WorkflowEntry
|
||||
from dify_graph.entities.workflow_node_execution import (
|
||||
WorkflowNodeExecution,
|
||||
@@ -48,7 +49,6 @@ from dify_graph.graph_events.base import GraphNodeEventBase
|
||||
from dify_graph.node_events.base import NodeRunResult
|
||||
from dify_graph.nodes.base.node import Node
|
||||
from dify_graph.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, build_http_request_config
|
||||
from dify_graph.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.repositories.workflow_node_execution_repository import OrderConfig
|
||||
from dify_graph.runtime import VariablePool
|
||||
from dify_graph.system_variable import SystemVariable
|
||||
|
||||
@@ -5,15 +5,15 @@ from datetime import datetime
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from dify_graph.entities.graph_config import NodeConfigDict
|
||||
from dify_graph.nodes import NodeType
|
||||
from dify_graph.nodes.trigger_schedule.entities import (
|
||||
from core.workflow.nodes.trigger_schedule.entities import (
|
||||
ScheduleConfig,
|
||||
SchedulePlanUpdate,
|
||||
TriggerScheduleNodeData,
|
||||
VisualConfig,
|
||||
)
|
||||
from dify_graph.nodes.trigger_schedule.exc import ScheduleConfigError, ScheduleNotFoundError
|
||||
from core.workflow.nodes.trigger_schedule.exc import ScheduleConfigError, ScheduleNotFoundError
|
||||
from dify_graph.entities.graph_config import NodeConfigDict
|
||||
from dify_graph.nodes import NodeType
|
||||
from libs.schedule_utils import calculate_next_run_at, convert_12h_to_24h
|
||||
from models.account import Account, TenantAccountJoin
|
||||
from models.trigger import WorkflowSchedulePlan
|
||||
|
||||
@@ -16,9 +16,9 @@ from core.trigger.debug.events import PluginTriggerDebugEvent
|
||||
from core.trigger.provider import PluginTriggerProviderController
|
||||
from core.trigger.trigger_manager import TriggerManager
|
||||
from core.trigger.utils.encryption import create_trigger_provider_encrypter_for_subscription
|
||||
from core.workflow.nodes.trigger_plugin.entities import TriggerEventNodeData
|
||||
from dify_graph.entities.graph_config import NodeConfigDict
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.nodes.trigger_plugin.entities import TriggerEventNodeData
|
||||
from extensions.ext_database import db
|
||||
from extensions.ext_redis import redis_client
|
||||
from models.model import App
|
||||
|
||||
@@ -16,15 +16,15 @@ from werkzeug.exceptions import RequestEntityTooLarge
|
||||
from configs import dify_config
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom
|
||||
from core.tools.tool_file_manager import ToolFileManager
|
||||
from dify_graph.entities.graph_config import NodeConfigDict
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.file.models import FileTransferMethod
|
||||
from dify_graph.nodes.trigger_webhook.entities import (
|
||||
from core.workflow.nodes.trigger_webhook.entities import (
|
||||
ContentType,
|
||||
WebhookBodyParameter,
|
||||
WebhookData,
|
||||
WebhookParameter,
|
||||
)
|
||||
from dify_graph.entities.graph_config import NodeConfigDict
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.file.models import FileTransferMethod
|
||||
from dify_graph.variables.types import ArrayValidation, SegmentType
|
||||
from enums.quota_type import QuotaType
|
||||
from extensions.ext_database import db
|
||||
|
||||
@@ -14,6 +14,7 @@ from core.app.apps.workflow.app_config_manager import WorkflowAppConfigManager
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom, UserFrom, build_dify_run_context
|
||||
from core.repositories import DifyCoreRepositoryFactory
|
||||
from core.repositories.human_input_repository import HumanInputFormRepositoryImpl
|
||||
from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
|
||||
from core.workflow.workflow_entry import WorkflowEntry
|
||||
from dify_graph.entities import GraphInitParams, WorkflowNodeExecution
|
||||
from dify_graph.entities.graph_config import NodeConfigDict
|
||||
@@ -34,7 +35,6 @@ from dify_graph.nodes.human_input.entities import (
|
||||
)
|
||||
from dify_graph.nodes.human_input.enums import HumanInputFormKind
|
||||
from dify_graph.nodes.human_input.human_input_node import HumanInputNode
|
||||
from dify_graph.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.nodes.start.entities import StartNodeData
|
||||
from dify_graph.repositories.human_input_form_repository import FormCreateParams
|
||||
from dify_graph.runtime import GraphRuntimeState, VariablePool
|
||||
|
||||
@@ -25,8 +25,8 @@ from core.trigger.debug.events import PluginTriggerDebugEvent, build_plugin_pool
|
||||
from core.trigger.entities.entities import TriggerProviderEntity
|
||||
from core.trigger.provider import PluginTriggerProviderController
|
||||
from core.trigger.trigger_manager import TriggerManager
|
||||
from core.workflow.nodes.trigger_plugin.entities import TriggerEventNodeData
|
||||
from dify_graph.enums import NodeType, WorkflowExecutionStatus
|
||||
from dify_graph.nodes.trigger_plugin.entities import TriggerEventNodeData
|
||||
from enums.quota_type import QuotaType, unlimited
|
||||
from models.enums import (
|
||||
AppTriggerType,
|
||||
|
||||
@@ -3,7 +3,7 @@ import logging
|
||||
from celery import shared_task
|
||||
|
||||
from core.db.session_factory import session_factory
|
||||
from dify_graph.nodes.trigger_schedule.exc import (
|
||||
from core.workflow.nodes.trigger_schedule.exc import (
|
||||
ScheduleExecutionError,
|
||||
ScheduleNotFoundError,
|
||||
TenantOwnerNotFoundError,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import time
|
||||
import uuid
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom, UserFrom
|
||||
from core.tools.utils.configuration import ToolParameterConfigurationManager
|
||||
@@ -87,17 +87,20 @@ def test_tool_variable_invoke():
|
||||
}
|
||||
)
|
||||
|
||||
ToolParameterConfigurationManager.decrypt_tool_parameters = MagicMock(return_value={"format": "%Y-%m-%d %H:%M:%S"})
|
||||
|
||||
node.graph_runtime_state.variable_pool.add(["1", "args1"], "1+1")
|
||||
|
||||
# execute node
|
||||
result = node._run()
|
||||
for item in result:
|
||||
if isinstance(item, StreamCompletedEvent):
|
||||
assert item.node_run_result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert item.node_run_result.outputs is not None
|
||||
assert item.node_run_result.outputs.get("text") is not None
|
||||
with patch.object(
|
||||
ToolParameterConfigurationManager,
|
||||
"decrypt_tool_parameters",
|
||||
return_value={"format": "%Y-%m-%d %H:%M:%S"},
|
||||
):
|
||||
# execute node
|
||||
result = node._run()
|
||||
for item in result:
|
||||
if isinstance(item, StreamCompletedEvent):
|
||||
assert item.node_run_result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert item.node_run_result.outputs is not None
|
||||
assert item.node_run_result.outputs.get("text") is not None
|
||||
|
||||
|
||||
def test_tool_mixed_invoke():
|
||||
@@ -121,12 +124,15 @@ def test_tool_mixed_invoke():
|
||||
}
|
||||
)
|
||||
|
||||
ToolParameterConfigurationManager.decrypt_tool_parameters = MagicMock(return_value={"format": "%Y-%m-%d %H:%M:%S"})
|
||||
|
||||
# execute node
|
||||
result = node._run()
|
||||
for item in result:
|
||||
if isinstance(item, StreamCompletedEvent):
|
||||
assert item.node_run_result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert item.node_run_result.outputs is not None
|
||||
assert item.node_run_result.outputs.get("text") is not None
|
||||
with patch.object(
|
||||
ToolParameterConfigurationManager,
|
||||
"decrypt_tool_parameters",
|
||||
return_value={"format": "%Y-%m-%d %H:%M:%S"},
|
||||
):
|
||||
# execute node
|
||||
result = node._run()
|
||||
for item in result:
|
||||
if isinstance(item, StreamCompletedEvent):
|
||||
assert item.node_run_result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert item.node_run_result.outputs is not None
|
||||
assert item.node_run_result.outputs.get("text") is not None
|
||||
|
||||
@@ -6,7 +6,7 @@ import uuid
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -738,6 +738,30 @@ class TestWorkflowResponseConverterServiceApiTruncation:
|
||||
assert not response.data.process_data_truncated
|
||||
assert not response.data.outputs_truncated
|
||||
|
||||
def test_trigger_plugin_start_event_uses_provider_id_for_icon(self):
|
||||
converter = self.create_test_converter(InvokeFrom.WEB_APP)
|
||||
event = QueueNodeStartedEvent(
|
||||
node_execution_id=str(uuid.uuid4()),
|
||||
node_id="trigger-node",
|
||||
node_title="Trigger Node",
|
||||
node_type=NodeType.TRIGGER_PLUGIN,
|
||||
start_at=naive_utc_now(),
|
||||
in_iteration_id=None,
|
||||
in_loop_id=None,
|
||||
provider_type="",
|
||||
provider_id="provider-1",
|
||||
)
|
||||
|
||||
with patch(
|
||||
"core.app.apps.common.workflow_response_converter.TriggerManager.get_trigger_plugin_icon",
|
||||
return_value="https://example.com/icon.png",
|
||||
) as get_trigger_plugin_icon:
|
||||
response = converter.workflow_node_start_to_stream_response(event=event, task_id="task-1")
|
||||
|
||||
assert response is not None
|
||||
assert response.data.extras["icon"] == "https://example.com/icon.png"
|
||||
get_trigger_plugin_icon.assert_called_once_with("test_tenant", "provider-1")
|
||||
|
||||
def test_service_api_iteration_events_no_truncation(self):
|
||||
"""Test that Service API doesn't truncate iteration events."""
|
||||
converter = self.create_test_converter(InvokeFrom.SERVICE_API)
|
||||
|
||||
@@ -6,7 +6,7 @@ import pytest
|
||||
import pytz
|
||||
|
||||
from core.trigger.debug import event_selectors
|
||||
from dify_graph.nodes.trigger_schedule.entities import ScheduleConfig
|
||||
from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig
|
||||
|
||||
|
||||
class _DummyRedis:
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import pytest
|
||||
|
||||
# Ensures that all node classes are imported.
|
||||
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
|
||||
from dify_graph.entities.base_node_data import BaseNodeData
|
||||
from dify_graph.enums import NodeType
|
||||
from dify_graph.nodes.base.node import Node
|
||||
|
||||
# Ensures that all node classes are imported.
|
||||
from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
|
||||
|
||||
# Ensure `NODE_TYPE_CLASSES_MAPPING` is used and not automatically removed.
|
||||
_ = NODE_TYPE_CLASSES_MAPPING
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom, UserFrom
|
||||
from core.workflow.nodes.trigger_plugin.entities import TriggerEventNodeData
|
||||
from core.workflow.nodes.trigger_plugin.trigger_event_node import TriggerEventNode
|
||||
from dify_graph.entities.graph_init_params import DIFY_RUN_CONTEXT_KEY, GraphInitParams
|
||||
from dify_graph.graph_events import NodeRunStartedEvent
|
||||
from dify_graph.runtime.graph_runtime_state import GraphRuntimeState
|
||||
from dify_graph.runtime.variable_pool import VariablePool
|
||||
from dify_graph.system_variable import SystemVariable
|
||||
|
||||
|
||||
def create_trigger_event_node(node_data: TriggerEventNodeData) -> TriggerEventNode:
|
||||
node_config = {
|
||||
"id": "trigger-node",
|
||||
"data": node_data.model_dump(),
|
||||
}
|
||||
graph_init_params = GraphInitParams(
|
||||
workflow_id="workflow-1",
|
||||
graph_config={},
|
||||
run_context={
|
||||
DIFY_RUN_CONTEXT_KEY: {
|
||||
"tenant_id": "tenant-1",
|
||||
"app_id": "app-1",
|
||||
"user_id": "user-1",
|
||||
"user_from": UserFrom.ACCOUNT,
|
||||
"invoke_from": InvokeFrom.SERVICE_API,
|
||||
}
|
||||
},
|
||||
call_depth=0,
|
||||
)
|
||||
runtime_state = GraphRuntimeState(
|
||||
variable_pool=VariablePool(
|
||||
system_variables=SystemVariable.default(),
|
||||
user_inputs={},
|
||||
),
|
||||
start_at=0,
|
||||
)
|
||||
return TriggerEventNode(
|
||||
id="trigger-node",
|
||||
config=node_config,
|
||||
graph_init_params=graph_init_params,
|
||||
graph_runtime_state=runtime_state,
|
||||
)
|
||||
|
||||
|
||||
def test_trigger_event_start_event_carries_provider_metadata() -> None:
|
||||
node = create_trigger_event_node(
|
||||
TriggerEventNodeData(
|
||||
title="Plugin Trigger",
|
||||
provider_id="provider-1",
|
||||
plugin_id="plugin-1",
|
||||
event_name="event.created",
|
||||
subscription_id="subscription-1",
|
||||
plugin_unique_identifier="plugin/provider",
|
||||
event_parameters={},
|
||||
)
|
||||
)
|
||||
|
||||
start_event = next(node.run())
|
||||
|
||||
assert isinstance(start_event, NodeRunStartedEvent)
|
||||
assert start_event.provider_id == "provider-1"
|
||||
assert start_event.extras == {"provider_id": "provider-1"}
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from dify_graph.nodes.trigger_webhook.entities import (
|
||||
from core.workflow.nodes.trigger_webhook.entities import (
|
||||
ContentType,
|
||||
Method,
|
||||
WebhookBodyParameter,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import pytest
|
||||
|
||||
from dify_graph.entities.exc import BaseNodeError
|
||||
from dify_graph.nodes.trigger_webhook.exc import (
|
||||
from core.workflow.nodes.trigger_webhook.exc import (
|
||||
WebhookConfigError,
|
||||
WebhookNodeError,
|
||||
WebhookNotFoundError,
|
||||
WebhookTimeoutError,
|
||||
)
|
||||
from dify_graph.entities.exc import BaseNodeError
|
||||
|
||||
|
||||
def test_webhook_node_error_inheritance():
|
||||
@@ -149,7 +149,7 @@ def test_webhook_error_attributes():
|
||||
assert WebhookConfigError.__name__ == "WebhookConfigError"
|
||||
|
||||
# Test that all error classes have proper __module__
|
||||
expected_module = "dify_graph.nodes.trigger_webhook.exc"
|
||||
expected_module = "core.workflow.nodes.trigger_webhook.exc"
|
||||
assert WebhookNodeError.__module__ == expected_module
|
||||
assert WebhookTimeoutError.__module__ == expected_module
|
||||
assert WebhookNotFoundError.__module__ == expected_module
|
||||
|
||||
@@ -9,15 +9,15 @@ when passing files to downstream LLM nodes.
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom, UserFrom
|
||||
from dify_graph.entities.graph_init_params import DIFY_RUN_CONTEXT_KEY, GraphInitParams
|
||||
from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus
|
||||
from dify_graph.nodes.trigger_webhook.entities import (
|
||||
from core.workflow.nodes.trigger_webhook.entities import (
|
||||
ContentType,
|
||||
Method,
|
||||
WebhookBodyParameter,
|
||||
WebhookData,
|
||||
)
|
||||
from dify_graph.nodes.trigger_webhook.node import TriggerWebhookNode
|
||||
from core.workflow.nodes.trigger_webhook.node import TriggerWebhookNode
|
||||
from dify_graph.entities.graph_init_params import DIFY_RUN_CONTEXT_KEY, GraphInitParams
|
||||
from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus
|
||||
from dify_graph.runtime.graph_runtime_state import GraphRuntimeState
|
||||
from dify_graph.runtime.variable_pool import VariablePool
|
||||
from dify_graph.system_variable import SystemVariable
|
||||
@@ -130,8 +130,8 @@ def test_webhook_node_file_conversion_to_file_variable():
|
||||
# Mock the file factory and variable factory
|
||||
with (
|
||||
patch("factories.file_factory.build_from_mapping") as mock_file_factory,
|
||||
patch("dify_graph.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory,
|
||||
patch("dify_graph.nodes.trigger_webhook.node.FileVariable") as mock_file_variable,
|
||||
patch("core.workflow.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory,
|
||||
patch("core.workflow.nodes.trigger_webhook.node.FileVariable") as mock_file_variable,
|
||||
):
|
||||
# Setup mocks
|
||||
mock_file_obj = Mock()
|
||||
@@ -322,8 +322,8 @@ def test_webhook_node_file_conversion_mixed_parameters():
|
||||
|
||||
with (
|
||||
patch("factories.file_factory.build_from_mapping") as mock_file_factory,
|
||||
patch("dify_graph.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory,
|
||||
patch("dify_graph.nodes.trigger_webhook.node.FileVariable") as mock_file_variable,
|
||||
patch("core.workflow.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory,
|
||||
patch("core.workflow.nodes.trigger_webhook.node.FileVariable") as mock_file_variable,
|
||||
):
|
||||
# Setup mocks for file
|
||||
mock_file_obj = Mock()
|
||||
@@ -390,8 +390,8 @@ def test_webhook_node_different_file_types():
|
||||
|
||||
with (
|
||||
patch("factories.file_factory.build_from_mapping") as mock_file_factory,
|
||||
patch("dify_graph.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory,
|
||||
patch("dify_graph.nodes.trigger_webhook.node.FileVariable") as mock_file_variable,
|
||||
patch("core.workflow.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory,
|
||||
patch("core.workflow.nodes.trigger_webhook.node.FileVariable") as mock_file_variable,
|
||||
):
|
||||
# Setup mocks for all files
|
||||
mock_file_objs = [Mock() for _ in range(3)]
|
||||
|
||||
@@ -3,17 +3,17 @@ from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom, UserFrom
|
||||
from dify_graph.entities.graph_init_params import DIFY_RUN_CONTEXT_KEY, GraphInitParams
|
||||
from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus
|
||||
from dify_graph.file import File, FileTransferMethod, FileType
|
||||
from dify_graph.nodes.trigger_webhook.entities import (
|
||||
from core.workflow.nodes.trigger_webhook.entities import (
|
||||
ContentType,
|
||||
Method,
|
||||
WebhookBodyParameter,
|
||||
WebhookData,
|
||||
WebhookParameter,
|
||||
)
|
||||
from dify_graph.nodes.trigger_webhook.node import TriggerWebhookNode
|
||||
from core.workflow.nodes.trigger_webhook.node import TriggerWebhookNode
|
||||
from dify_graph.entities.graph_init_params import DIFY_RUN_CONTEXT_KEY, GraphInitParams
|
||||
from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus
|
||||
from dify_graph.file import File, FileTransferMethod, FileType
|
||||
from dify_graph.runtime.graph_runtime_state import GraphRuntimeState
|
||||
from dify_graph.runtime.variable_pool import VariablePool
|
||||
from dify_graph.system_variable import SystemVariable
|
||||
|
||||
@@ -294,7 +294,7 @@ class TestFrontendBackendIntegration(unittest.TestCase):
|
||||
|
||||
def test_schedule_service_integration(self):
|
||||
"""Test integration with ScheduleService patterns."""
|
||||
from dify_graph.nodes.trigger_schedule.entities import VisualConfig
|
||||
from core.workflow.nodes.trigger_schedule.entities import VisualConfig
|
||||
from services.trigger.schedule_service import ScheduleService
|
||||
|
||||
# Test enhanced syntax through visual config conversion
|
||||
|
||||
@@ -5,8 +5,8 @@ from unittest.mock import MagicMock, Mock, patch
|
||||
import pytest
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from dify_graph.nodes.trigger_schedule.entities import ScheduleConfig, SchedulePlanUpdate, VisualConfig
|
||||
from dify_graph.nodes.trigger_schedule.exc import ScheduleConfigError
|
||||
from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig, SchedulePlanUpdate, VisualConfig
|
||||
from core.workflow.nodes.trigger_schedule.exc import ScheduleConfigError
|
||||
from events.event_handlers.sync_workflow_schedule_when_app_published import (
|
||||
sync_schedule_from_workflow,
|
||||
)
|
||||
@@ -136,7 +136,7 @@ class TestScheduleService(unittest.TestCase):
|
||||
|
||||
def test_update_schedule_not_found(self):
|
||||
"""Test updating a non-existent schedule raises exception."""
|
||||
from dify_graph.nodes.trigger_schedule.exc import ScheduleNotFoundError
|
||||
from core.workflow.nodes.trigger_schedule.exc import ScheduleNotFoundError
|
||||
|
||||
mock_session = MagicMock(spec=Session)
|
||||
mock_session.get.return_value = None
|
||||
@@ -172,7 +172,7 @@ class TestScheduleService(unittest.TestCase):
|
||||
|
||||
def test_delete_schedule_not_found(self):
|
||||
"""Test deleting a non-existent schedule raises exception."""
|
||||
from dify_graph.nodes.trigger_schedule.exc import ScheduleNotFoundError
|
||||
from core.workflow.nodes.trigger_schedule.exc import ScheduleNotFoundError
|
||||
|
||||
mock_session = MagicMock(spec=Session)
|
||||
mock_session.get.return_value = None
|
||||
|
||||
Reference in New Issue
Block a user