Compare commits

...

3 Commits

Author SHA1 Message Date
-LAN-
b964db6bb6 test(*): Correct import path
Signed-off-by: -LAN- <laipz8200@outlook.com>
2025-04-25 22:43:48 +08:00
-LAN-
f20190ad56 refactor: Enhances workflow execution context handling
Adds workflow and execution context parameters to improve
repository filtering and record management. Introduces
new parameters such as 'workflow_id', 'triggered_from',
and creator details for better tracking of workflow
executions. Updates relevant services and generators to
pass these parameters.

Facilitates debugging and improves execution context
management across multiple components.

Signed-off-by: -LAN- <laipz8200@outlook.com>
2025-04-25 22:27:48 +08:00
-LAN-
03e61ba09f refacotr(workflow): move WorkflowNodeExecutionStatus from models to core.workflow.entities
Signed-off-by: -LAN- <laipz8200@outlook.com>
2025-04-25 21:30:32 +08:00
57 changed files with 324 additions and 86 deletions

View File

@@ -31,7 +31,7 @@ from extensions.ext_database import db
from factories import file_factory
from models.account import Account
from models.model import App, Conversation, EndUser, Message
from models.workflow import Workflow
from models.workflow import Workflow, WorkflowNodeExecutionTriggeredFrom
from services.conversation_service import ConversationService
from services.errors.message import MessageNotExistsError
@@ -167,6 +167,9 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
params={
"tenant_id": application_generate_entity.app_config.tenant_id,
"app_id": application_generate_entity.app_config.app_id,
"workflow_id": workflow.id,
# Default for advanced chat app
"triggered_from": WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN,
"session_factory": session_factory,
}
)
@@ -235,6 +238,9 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
params={
"tenant_id": application_generate_entity.app_config.tenant_id,
"app_id": application_generate_entity.app_config.app_id,
"workflow_id": workflow.id,
# For debugging
"triggered_from": WorkflowNodeExecutionTriggeredFrom.SINGLE_STEP,
"session_factory": session_factory,
}
)
@@ -301,6 +307,8 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
params={
"tenant_id": application_generate_entity.app_config.tenant_id,
"app_id": application_generate_entity.app_config.app_id,
"workflow_id": workflow.id,
"triggered_from": WorkflowNodeExecutionTriggeredFrom.SINGLE_STEP, # For debugging
"session_factory": session_factory,
}
)

View File

@@ -28,6 +28,7 @@ from core.repository.workflow_node_execution_repository import WorkflowNodeExecu
from extensions.ext_database import db
from factories import file_factory
from models import Account, App, EndUser, Workflow
from models.workflow import WorkflowNodeExecutionTriggeredFrom
logger = logging.getLogger(__name__)
@@ -142,6 +143,8 @@ class WorkflowAppGenerator(BaseAppGenerator):
params={
"tenant_id": application_generate_entity.app_config.tenant_id,
"app_id": application_generate_entity.app_config.app_id,
"workflow_id": workflow.id,
"triggered_from": WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN, # Default for workflow app
"session_factory": session_factory,
}
)
@@ -268,6 +271,8 @@ class WorkflowAppGenerator(BaseAppGenerator):
params={
"tenant_id": application_generate_entity.app_config.tenant_id,
"app_id": application_generate_entity.app_config.app_id,
"workflow_id": workflow.id,
"triggered_from": WorkflowNodeExecutionTriggeredFrom.SINGLE_STEP, # For debugging
"session_factory": session_factory,
}
)
@@ -333,6 +338,8 @@ class WorkflowAppGenerator(BaseAppGenerator):
params={
"tenant_id": application_generate_entity.app_config.tenant_id,
"app_id": application_generate_entity.app_config.app_id,
"workflow_id": workflow.id,
"triggered_from": WorkflowNodeExecutionTriggeredFrom.SINGLE_STEP, # For debugging
"session_factory": session_factory,
}
)

View File

@@ -6,8 +6,8 @@ from pydantic import BaseModel, ConfigDict
from core.model_runtime.entities.llm_entities import LLMResult
from core.model_runtime.utils.encoders import jsonable_encoder
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import AgentNodeStrategyInit
from models.workflow import WorkflowNodeExecutionStatus
class TaskState(BaseModel):

View File

@@ -51,6 +51,7 @@ from core.ops.entities.trace_entity import TraceTaskName
from core.ops.ops_trace_manager import TraceQueueManager, TraceTask
from core.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository
from core.tools.tool_manager import ToolManager
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey
from core.workflow.enums import SystemVariableKey
from core.workflow.nodes import NodeType
@@ -62,7 +63,6 @@ from models.model import EndUser
from models.workflow import (
Workflow,
WorkflowNodeExecution,
WorkflowNodeExecutionStatus,
WorkflowNodeExecutionTriggeredFrom,
WorkflowRun,
WorkflowRunStatus,

View File

@@ -32,6 +32,7 @@ from core.ops.utils import filter_none_values
from core.repository.repository_factory import RepositoryFactory
from extensions.ext_database import db
from models.model import EndUser
from models.workflow import WorkflowNodeExecutionTriggeredFrom
logger = logging.getLogger(__name__)
@@ -114,7 +115,13 @@ class LangFuseDataTrace(BaseTraceInstance):
# through workflow_run_id get all_nodes_execution using repository
session_factory = sessionmaker(bind=db.engine)
workflow_node_execution_repository = RepositoryFactory.create_workflow_node_execution_repository(
params={"tenant_id": trace_info.tenant_id, "session_factory": session_factory},
params={
"tenant_id": trace_info.tenant_id,
"app_id": trace_info.metadata.get("app_id"),
"workflow_id": trace_info.workflow_data.id,
"triggered_from": WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN,
"session_factory": session_factory,
},
)
# Get all executions for this workflow run
@@ -233,7 +240,7 @@ class LangFuseDataTrace(BaseTraceInstance):
self.add_generation(langfuse_generation_data=node_generation_data)
def message_trace(self, trace_info: MessageTraceInfo, **kwargs):
def message_trace(self, trace_info: MessageTraceInfo):
# get message file data
file_list = trace_info.file_list
metadata = trace_info.metadata

View File

@@ -31,6 +31,7 @@ from core.ops.utils import filter_none_values, generate_dotted_order
from core.repository.repository_factory import RepositoryFactory
from extensions.ext_database import db
from models.model import EndUser, MessageFile
from models.workflow import WorkflowNodeExecutionTriggeredFrom
logger = logging.getLogger(__name__)
@@ -141,6 +142,8 @@ class LangSmithDataTrace(BaseTraceInstance):
params={
"tenant_id": trace_info.tenant_id,
"app_id": trace_info.metadata.get("app_id"),
"workflow_id": trace_info.workflow_data.id,
"triggered_from": WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN,
"session_factory": session_factory,
},
)

View File

@@ -25,6 +25,7 @@ from core.ops.entities.trace_entity import (
from core.repository.repository_factory import RepositoryFactory
from extensions.ext_database import db
from models.model import EndUser, MessageFile
from models.workflow import WorkflowNodeExecutionTriggeredFrom
logger = logging.getLogger(__name__)
@@ -154,6 +155,8 @@ class OpikDataTrace(BaseTraceInstance):
params={
"tenant_id": trace_info.tenant_id,
"app_id": trace_info.metadata.get("app_id"),
"workflow_id": trace_info.workflow_data.id,
"triggered_from": WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN,
"session_factory": session_factory,
},
)

View File

@@ -0,0 +1,3 @@
from .node_execution_entities import WorkflowNodeExecutionStatus
__all__ = ["WorkflowNodeExecutionStatus"]

View File

@@ -5,7 +5,8 @@ from typing import Any, Optional
from pydantic import BaseModel
from core.model_runtime.entities.llm_entities import LLMUsage
from models.workflow import WorkflowNodeExecutionStatus
from .node_execution_entities import WorkflowNodeExecutionStatus
class NodeRunMetadataKey(StrEnum):

View File

@@ -0,0 +1,64 @@
from datetime import datetime
from enum import StrEnum
from typing import Any, Optional
from pydantic import BaseModel, Field
class WorkflowNodeExecutionStatus(StrEnum):
"""
Workflow Node Execution Status Enum
"""
RUNNING = "running"
SUCCEEDED = "succeeded"
FAILED = "failed"
EXCEPTION = "exception"
RETRY = "retry"
class WorkflowNodeExecution(BaseModel):
"""
Core Workflow Node Execution Model
A minimal Pydantic model for workflow node execution that doesn't contain
fields like tenant_id, app_id, etc. that aren't needed by the pure workflow core.
This model contains only the essential fields needed for the workflow core functionality.
"""
id: str = Field(..., description="Execution ID")
node_execution_id: Optional[str] = Field(None, description="Node execution ID, used for tracking execution")
index: int = Field(..., description="Execution sequence number, used for displaying Tracing Node order")
predecessor_node_id: Optional[str] = Field(
None, description="Predecessor node ID, used for displaying execution path"
)
node_id: str = Field(..., description="Node ID")
node_type: str = Field(..., description="Node type, such as 'start'")
title: str = Field(..., description="Node title")
# Data fields
inputs: Optional[dict[str, Any]] = Field(None, description="All predecessor node variable content used in the node")
process_data: Optional[dict[str, Any]] = Field(None, description="Node process data")
outputs: Optional[dict[str, Any]] = Field(None, description="Node output variables")
# Status and error information
status: WorkflowNodeExecutionStatus = Field(WorkflowNodeExecutionStatus.RUNNING, description="Execution status")
error: Optional[str] = Field(None, description="Error reason if status is failed")
error_type: Optional[str] = Field(None, description="Error type if status is failed")
# Timing and performance
elapsed_time: float = Field(0.0, description="Time consumption (s)")
created_at: datetime = Field(default_factory=datetime.now, description="Run time")
finished_at: Optional[datetime] = Field(None, description="End time")
# Metadata
execution_metadata: Optional[dict[str, Any]] = Field(None, description="Execution metadata")
# For iteration/loop tracking
workflow_run_id: Optional[str] = Field(None, description="Workflow run ID")
class Config:
"""Pydantic model configuration"""
arbitrary_types_allowed = True

View File

@@ -5,8 +5,8 @@ from typing import Optional
from pydantic import BaseModel, Field
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from models.workflow import WorkflowNodeExecutionStatus
class RouteNodeState(BaseModel):

View File

@@ -14,6 +14,7 @@ from flask import Flask, current_app
from configs import dify_config
from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunMetadataKey, NodeRunResult
from core.workflow.entities.variable_pool import VariablePool, VariableValue
from core.workflow.graph_engine.condition_handlers.condition_manager import ConditionManager
@@ -54,7 +55,7 @@ from core.workflow.nodes.event import RunCompletedEvent, RunRetrieverResourceEve
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
from extensions.ext_database import db
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
logger = logging.getLogger(__name__)

View File

@@ -13,6 +13,7 @@ from core.provider_manager import ProviderManager
from core.tools.entities.tool_entities import ToolParameter, ToolProviderType
from core.tools.tool_manager import ToolManager
from core.variables.segments import StringSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
@@ -25,7 +26,6 @@ from core.workflow.utils.variable_template_parser import VariableTemplateParser
from extensions.ext_database import db
from factories.agent_factory import get_plugin_agent_strategy
from models.model import Conversation
from models.workflow import WorkflowNodeExecutionStatus
class AgentNode(ToolNode):

View File

@@ -2,6 +2,7 @@ from collections.abc import Mapping, Sequence
from typing import Any, cast
from core.variables import ArrayFileSegment, FileSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.answer.answer_stream_generate_router import AnswerStreamGeneratorRouter
from core.workflow.nodes.answer.entities import (
@@ -13,7 +14,6 @@ from core.workflow.nodes.answer.entities import (
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.utils.variable_template_parser import VariableTemplateParser
from models.workflow import WorkflowNodeExecutionStatus
class AnswerNode(BaseNode[AnswerNodeData]):

View File

@@ -3,10 +3,10 @@ from abc import abstractmethod
from collections.abc import Generator, Mapping, Sequence
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.enums import CONTINUE_ON_ERROR_NODE_TYPE, RETRY_ON_ERROR_NODE_TYPE, NodeType
from core.workflow.nodes.event import NodeEvent, RunCompletedEvent
from models.workflow import WorkflowNodeExecutionStatus
from .entities import BaseNodeData

View File

@@ -7,11 +7,11 @@ from core.helper.code_executor.code_node_provider import CodeNodeProvider
from core.helper.code_executor.javascript.javascript_code_provider import JavascriptCodeProvider
from core.helper.code_executor.python3.python3_code_provider import Python3CodeProvider
from core.variables.segments import ArrayFileSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.code.entities import CodeNodeData
from core.workflow.nodes.enums import NodeType
from models.workflow import WorkflowNodeExecutionStatus
from .exc import (
CodeNodeError,

View File

@@ -23,10 +23,10 @@ from core.file import File, FileTransferMethod, file_manager
from core.helper import ssrf_proxy
from core.variables import ArrayFileSegment
from core.variables.segments import FileSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from models.workflow import WorkflowNodeExecutionStatus
from .entities import DocumentExtractorNodeData
from .exc import DocumentExtractorError, FileDownloadError, TextExtractionError, UnsupportedFileTypeError

View File

@@ -1,8 +1,8 @@
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.end.entities import EndNodeData
from core.workflow.nodes.enums import NodeType
from models.workflow import WorkflowNodeExecutionStatus
class EndNode(BaseNode[EndNodeData]):

View File

@@ -3,8 +3,8 @@ from datetime import datetime
from pydantic import BaseModel, Field
from core.model_runtime.entities.llm_entities import LLMUsage
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from models.workflow import WorkflowNodeExecutionStatus
class RunCompletedEvent(BaseModel):

View File

@@ -6,6 +6,7 @@ from typing import Any, Optional
from configs import dify_config
from core.file import File, FileTransferMethod
from core.tools.tool_file_manager import ToolFileManager
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.entities.variable_entities import VariableSelector
from core.workflow.nodes.base import BaseNode
@@ -13,7 +14,6 @@ from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.http_request.executor import Executor
from core.workflow.utils import variable_template_parser
from factories import file_factory
from models.workflow import WorkflowNodeExecutionStatus
from .entities import (
HttpRequestNodeData,

View File

@@ -2,6 +2,7 @@ from typing import Literal
from typing_extensions import deprecated
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.nodes.base import BaseNode
@@ -9,7 +10,6 @@ from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.if_else.entities import IfElseNodeData
from core.workflow.utils.condition.entities import Condition
from core.workflow.utils.condition.processor import ConditionProcessor
from models.workflow import WorkflowNodeExecutionStatus
class IfElseNode(BaseNode[IfElseNodeData]):

View File

@@ -11,6 +11,7 @@ from flask import Flask, current_app
from configs import dify_config
from core.variables import ArrayVariable, IntegerVariable, NoneVariable
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import (
NodeRunMetadataKey,
NodeRunResult,
@@ -37,7 +38,6 @@ from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.event import NodeEvent, RunCompletedEvent
from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData
from models.workflow import WorkflowNodeExecutionStatus
from .exc import (
InvalidIteratorValueError,

View File

@@ -1,8 +1,8 @@
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.iteration.entities import IterationStartNodeData
from models.workflow import WorkflowNodeExecutionStatus
class IterationStartNode(BaseNode[IterationStartNodeData]):

View File

@@ -23,6 +23,7 @@ from core.rag.entities.metadata_entities import Condition, MetadataCondition
from core.rag.retrieval.dataset_retrieval import DatasetRetrieval
from core.rag.retrieval.retrieval_methods import RetrievalMethod
from core.variables import StringSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.event.event import ModelInvokeCompletedEvent
@@ -41,7 +42,6 @@ from extensions.ext_database import db
from extensions.ext_redis import redis_client
from libs.json_in_md_parser import parse_and_check_json_markdown
from models.dataset import Dataset, DatasetMetadata, Document, RateLimitLog
from models.workflow import WorkflowNodeExecutionStatus
from services.feature_service import FeatureService
from .entities import KnowledgeRetrievalNodeData, ModelConfig

View File

@@ -3,10 +3,10 @@ from typing import Any, Literal, Union
from core.file import File
from core.variables import ArrayFileSegment, ArrayNumberSegment, ArrayStringSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from models.workflow import WorkflowNodeExecutionStatus
from .entities import ListOperatorNodeData
from .exc import InvalidConditionError, InvalidFilterValueError, InvalidKeyError, ListOperatorError

View File

@@ -51,6 +51,7 @@ from core.variables import (
StringSegment,
)
from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult
from core.workflow.entities.variable_entities import VariableSelector
from core.workflow.entities.variable_pool import VariablePool
@@ -75,7 +76,6 @@ from core.workflow.utils.variable_template_parser import VariableTemplateParser
from extensions.ext_database import db
from models.model import Conversation
from models.provider import Provider, ProviderType
from models.workflow import WorkflowNodeExecutionStatus
from .entities import (
LLMNodeChatModelMessage,

View File

@@ -1,8 +1,8 @@
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.loop.entities import LoopEndNodeData
from models.workflow import WorkflowNodeExecutionStatus
class LoopEndNode(BaseNode[LoopEndNodeData]):

View File

@@ -15,6 +15,7 @@ from core.variables import (
SegmentType,
StringSegment,
)
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult
from core.workflow.graph_engine.entities.event import (
BaseGraphEvent,
@@ -37,7 +38,6 @@ from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.event import NodeEvent, RunCompletedEvent
from core.workflow.nodes.loop.entities import LoopNodeData
from core.workflow.utils.condition.processor import ConditionProcessor
from models.workflow import WorkflowNodeExecutionStatus
if TYPE_CHECKING:
from core.workflow.entities.variable_pool import VariablePool

View File

@@ -1,8 +1,8 @@
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.loop.entities import LoopStartNodeData
from models.workflow import WorkflowNodeExecutionStatus
class LoopStartNode(BaseNode[LoopStartNodeData]):

View File

@@ -25,13 +25,13 @@ from core.prompt.advanced_prompt_transform import AdvancedPromptTransform
from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate
from core.prompt.simple_prompt_transform import ModelMode
from core.prompt.utils.prompt_message_util import PromptMessageUtil
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.llm import LLMNode, ModelConfig
from core.workflow.utils import variable_template_parser
from extensions.ext_database import db
from models.workflow import WorkflowNodeExecutionStatus
from .entities import ParameterExtractorNodeData
from .exc import (

View File

@@ -10,6 +10,7 @@ from core.model_runtime.utils.encoders import jsonable_encoder
from core.prompt.advanced_prompt_transform import AdvancedPromptTransform
from core.prompt.simple_prompt_transform import ModelMode
from core.prompt.utils.prompt_message_util import PromptMessageUtil
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.event import ModelInvokeCompletedEvent
@@ -20,7 +21,6 @@ from core.workflow.nodes.llm import (
)
from core.workflow.utils.variable_template_parser import VariableTemplateParser
from libs.json_in_md_parser import parse_and_check_json_markdown
from models.workflow import WorkflowNodeExecutionStatus
from .entities import QuestionClassifierNodeData
from .exc import InvalidModelTypeError

View File

@@ -1,9 +1,9 @@
from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.start.entities import StartNodeData
from models.workflow import WorkflowNodeExecutionStatus
class StartNode(BaseNode[StartNodeData]):

View File

@@ -3,11 +3,11 @@ from collections.abc import Mapping, Sequence
from typing import Any, Optional
from core.helper.code_executor.code_executor import CodeExecutionError, CodeExecutor, CodeLanguage
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.template_transform.entities import TemplateTransformNodeData
from models.workflow import WorkflowNodeExecutionStatus
MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH = int(os.environ.get("TEMPLATE_TRANSFORM_MAX_LENGTH", "80000"))

View File

@@ -14,6 +14,7 @@ from core.tools.tool_engine import ToolEngine
from core.tools.utils.message_transformer import ToolFileMessageTransformer
from core.variables.segments import ArrayAnySegment
from core.variables.variables import ArrayAnyVariable
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
@@ -25,7 +26,6 @@ from core.workflow.utils.variable_template_parser import VariableTemplateParser
from extensions.ext_database import db
from factories import file_factory
from models import ToolFile
from models.workflow import WorkflowNodeExecutionStatus
from services.tools.builtin_tools_manage_service import BuiltinToolManageService
from .entities import ToolNodeData

View File

@@ -1,8 +1,8 @@
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.variable_aggregator.entities import VariableAssignerNodeData
from models.workflow import WorkflowNodeExecutionStatus
class VariableAggregatorNode(BaseNode[VariableAssignerNodeData]):

View File

@@ -1,11 +1,11 @@
from core.variables import SegmentType, Variable
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.variable_assigner.common import helpers as common_helpers
from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError
from factories import variable_factory
from models.workflow import WorkflowNodeExecutionStatus
from .node_data import VariableAssignerData, WriteMode

View File

@@ -5,12 +5,12 @@ from typing import Any, cast
from core.app.entities.app_invoke_entities import InvokeFrom
from core.variables import SegmentType, Variable
from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.base import BaseNode
from core.workflow.nodes.enums import NodeType
from core.workflow.nodes.variable_assigner.common import helpers as common_helpers
from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError
from models.workflow import WorkflowNodeExecutionStatus
from . import helpers
from .constants import EMPTY_VALUE_MAPPING

View File

@@ -85,7 +85,6 @@ from .workflow import (
WorkflowAppLog,
WorkflowAppLogCreatedFrom,
WorkflowNodeExecution,
WorkflowNodeExecutionStatus,
WorkflowNodeExecutionTriggeredFrom,
WorkflowRun,
WorkflowRunStatus,

View File

@@ -524,18 +524,6 @@ class WorkflowNodeExecutionTriggeredFrom(StrEnum):
WORKFLOW_RUN = "workflow-run"
class WorkflowNodeExecutionStatus(StrEnum):
"""
Workflow Node Execution Status Enum
"""
RUNNING = "running"
SUCCEEDED = "succeeded"
FAILED = "failed"
EXCEPTION = "exception"
RETRY = "retry"
class WorkflowNodeExecution(Base):
"""
Workflow Node Execution

View File

@@ -11,7 +11,7 @@ from typing import Any
from sqlalchemy.orm import sessionmaker
from configs import dify_config
from core.repository.repository_factory import RepositoryFactory
from core.repository import RepositoryFactory
from extensions.ext_database import db
from repositories.workflow_node_execution import SQLAlchemyWorkflowNodeExecutionRepository
@@ -58,6 +58,11 @@ def create_workflow_node_execution_repository(params: Mapping[str, Any]) -> SQLA
params: Parameters for creating the repository, including:
- tenant_id: Required. The tenant ID for multi-tenancy.
- app_id: Optional. The application ID for filtering.
- workflow_id: Optional. The workflow ID for filtering.
- triggered_from: Optional. The triggered_from value for filtering
(WorkflowNodeExecutionTriggeredFrom enum).
- created_by_role: Optional. The creator role for new executions.
- created_by: Optional. The creator ID for new executions.
- session_factory: Optional. A SQLAlchemy sessionmaker instance. If not provided,
a new sessionmaker will be created using the global database engine.
@@ -74,6 +79,10 @@ def create_workflow_node_execution_repository(params: Mapping[str, Any]) -> SQLA
# Extract optional parameters
app_id = params.get("app_id")
workflow_id = params.get("workflow_id")
triggered_from = params.get("triggered_from")
created_by_role = params.get("created_by_role")
created_by = params.get("created_by")
# Use the session_factory from params if provided, otherwise create one using the global db engine
session_factory = params.get("session_factory")
@@ -83,5 +92,11 @@ def create_workflow_node_execution_repository(params: Mapping[str, Any]) -> SQLA
# Create and return the repository
return SQLAlchemyWorkflowNodeExecutionRepository(
session_factory=session_factory, tenant_id=tenant_id, app_id=app_id
session_factory=session_factory,
tenant_id=tenant_id,
app_id=app_id,
workflow_id=workflow_id,
triggered_from=triggered_from,
created_by_role=created_by_role,
created_by=created_by,
)

View File

@@ -11,7 +11,8 @@ from sqlalchemy.engine import Engine
from sqlalchemy.orm import sessionmaker
from core.repository.workflow_node_execution_repository import OrderConfig
from models.workflow import WorkflowNodeExecution, WorkflowNodeExecutionStatus, WorkflowNodeExecutionTriggeredFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from models.workflow import WorkflowNodeExecution, WorkflowNodeExecutionTriggeredFrom
logger = logging.getLogger(__name__)
@@ -25,14 +26,27 @@ class SQLAlchemyWorkflowNodeExecutionRepository:
to the database. This prevents long-running connections in the workflow core.
"""
def __init__(self, session_factory: sessionmaker | Engine, tenant_id: str, app_id: Optional[str] = None):
def __init__(
self,
session_factory: sessionmaker | Engine,
tenant_id: str,
app_id: str | None = None,
workflow_id: str | None = None,
triggered_from: WorkflowNodeExecutionTriggeredFrom | None = None,
created_by_role: str | None = None,
created_by: str | None = None,
):
"""
Initialize the repository with a SQLAlchemy sessionmaker or engine and tenant context.
Initialize the repository with a SQLAlchemy sessionmaker or engine and context parameters.
Args:
session_factory: SQLAlchemy sessionmaker or engine for creating sessions
tenant_id: Tenant ID for multi-tenancy
app_id: Optional app ID for filtering by application
app_id: App ID for filtering by application (optional)
workflow_id: Workflow ID for filtering by workflow (optional)
triggered_from: Triggered_from value (WorkflowNodeExecutionTriggeredFrom enum) (optional)
created_by_role: Creator role (e.g., 'account', 'end_user') (optional)
created_by: Creator ID (optional)
"""
# If an engine is provided, create a sessionmaker from it
if isinstance(session_factory, Engine):
@@ -46,6 +60,10 @@ class SQLAlchemyWorkflowNodeExecutionRepository:
self._tenant_id = tenant_id
self._app_id = app_id
self._workflow_id = workflow_id
self._triggered_from = triggered_from
self._created_by_role = created_by_role
self._created_by = created_by
def save(self, execution: WorkflowNodeExecution) -> None:
"""
@@ -55,14 +73,25 @@ class SQLAlchemyWorkflowNodeExecutionRepository:
execution: The WorkflowNodeExecution instance to save
"""
with self._session_factory() as session:
# Ensure tenant_id is set
if not execution.tenant_id:
execution.tenant_id = self._tenant_id
# Always set tenant_id from the repository context
execution.tenant_id = self._tenant_id
# Set app_id if provided and not already set
if self._app_id and not execution.app_id:
# Set other fields only if they are provided in the repository
if self._app_id is not None:
execution.app_id = self._app_id
if self._workflow_id is not None:
execution.workflow_id = self._workflow_id
if self._triggered_from is not None:
execution.triggered_from = self._triggered_from
if self._created_by_role is not None:
execution.created_by_role = self._created_by_role
if self._created_by is not None:
execution.created_by = self._created_by
session.add(execution)
session.commit()
@@ -82,9 +111,16 @@ class SQLAlchemyWorkflowNodeExecutionRepository:
WorkflowNodeExecution.tenant_id == self._tenant_id,
)
# Apply additional filters if provided
if self._app_id:
stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id)
if self._workflow_id:
stmt = stmt.where(WorkflowNodeExecution.workflow_id == self._workflow_id)
if self._triggered_from:
stmt = stmt.where(WorkflowNodeExecution.triggered_from == self._triggered_from)
return session.scalar(stmt)
def get_by_workflow_run(
@@ -108,12 +144,24 @@ class SQLAlchemyWorkflowNodeExecutionRepository:
stmt = select(WorkflowNodeExecution).where(
WorkflowNodeExecution.workflow_run_id == workflow_run_id,
WorkflowNodeExecution.tenant_id == self._tenant_id,
WorkflowNodeExecution.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN,
)
# Use the triggered_from from the instance if provided, otherwise use the default
if self._triggered_from:
stmt = stmt.where(WorkflowNodeExecution.triggered_from == self._triggered_from)
else:
# Default behavior for backward compatibility
stmt = stmt.where(
WorkflowNodeExecution.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN
)
# Apply additional filters if provided
if self._app_id:
stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id)
if self._workflow_id:
stmt = stmt.where(WorkflowNodeExecution.workflow_id == self._workflow_id)
# Apply ordering if provided
if order_config and order_config.order_by:
order_columns: list[UnaryExpression] = []
@@ -146,12 +194,24 @@ class SQLAlchemyWorkflowNodeExecutionRepository:
WorkflowNodeExecution.workflow_run_id == workflow_run_id,
WorkflowNodeExecution.tenant_id == self._tenant_id,
WorkflowNodeExecution.status == WorkflowNodeExecutionStatus.RUNNING,
WorkflowNodeExecution.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN,
)
# Use the triggered_from from the instance if provided, otherwise use the default
if self._triggered_from:
stmt = stmt.where(WorkflowNodeExecution.triggered_from == self._triggered_from)
else:
# Default behavior for backward compatibility
stmt = stmt.where(
WorkflowNodeExecution.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN
)
# Apply additional filters if provided
if self._app_id:
stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id)
if self._workflow_id:
stmt = stmt.where(WorkflowNodeExecution.workflow_id == self._workflow_id)
return session.scalars(stmt).all()
def update(self, execution: WorkflowNodeExecution) -> None:
@@ -162,35 +222,96 @@ class SQLAlchemyWorkflowNodeExecutionRepository:
execution: The WorkflowNodeExecution instance to update
"""
with self._session_factory() as session:
# Ensure tenant_id is set
if not execution.tenant_id:
execution.tenant_id = self._tenant_id
# Always set tenant_id from the repository context
execution.tenant_id = self._tenant_id
# Set app_id if provided and not already set
if self._app_id and not execution.app_id:
# Set other fields only if they are provided in the repository
if self._app_id is not None:
execution.app_id = self._app_id
if self._workflow_id is not None:
execution.workflow_id = self._workflow_id
if self._triggered_from is not None:
execution.triggered_from = self._triggered_from
if self._created_by_role is not None:
execution.created_by_role = self._created_by_role
if self._created_by is not None:
execution.created_by = self._created_by
session.merge(execution)
session.commit()
def update_context(
self,
app_id: str | None = None,
workflow_id: str | None = None,
triggered_from: WorkflowNodeExecutionTriggeredFrom | None = None,
created_by_role: str | None = None,
created_by: str | None = None,
) -> None:
"""
Update the repository's context parameters.
This method allows updating the repository's context parameters after initialization.
Only parameters that are not None will be updated.
Args:
app_id: New app ID for filtering
workflow_id: New workflow ID for filtering
triggered_from: New triggered_from value (WorkflowNodeExecutionTriggeredFrom enum)
created_by_role: New creator role
created_by: New creator ID
"""
if app_id is not None:
self._app_id = app_id
if workflow_id is not None:
self._workflow_id = workflow_id
if triggered_from is not None:
self._triggered_from = triggered_from
if created_by_role is not None:
self._created_by_role = created_by_role
if created_by is not None:
self._created_by = created_by
def clear(self) -> None:
"""
Clear all WorkflowNodeExecution records for the current tenant_id and app_id.
Clear all WorkflowNodeExecution records for the current tenant_id and other filters.
This method deletes all WorkflowNodeExecution records that match the tenant_id
and app_id (if provided) associated with this repository instance.
and other filters (app_id, workflow_id, triggered_from) associated with this repository instance.
"""
with self._session_factory() as session:
stmt = delete(WorkflowNodeExecution).where(WorkflowNodeExecution.tenant_id == self._tenant_id)
# Apply additional filters if provided
if self._app_id:
stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id)
if self._workflow_id:
stmt = stmt.where(WorkflowNodeExecution.workflow_id == self._workflow_id)
if self._triggered_from:
stmt = stmt.where(WorkflowNodeExecution.triggered_from == self._triggered_from)
result = session.execute(stmt)
session.commit()
# Build log message with all applied filters
filter_parts = []
if self._tenant_id:
filter_parts.append(f"tenant {self._tenant_id}")
if self._app_id:
filter_parts.append(f"app {self._app_id}")
if self._workflow_id:
filter_parts.append(f"workflow {self._workflow_id}")
if self._triggered_from:
filter_parts.append(f"triggered_from {self._triggered_from}")
filters_str = " and ".join(filter_parts)
deleted_count = result.rowcount
logger.info(
f"Cleared {deleted_count} workflow node execution records for tenant {self._tenant_id}"
+ (f" and app {self._app_id}" if self._app_id else "")
)
logger.info(f"Cleared {deleted_count} workflow node execution records for {filters_str}")

View File

@@ -133,6 +133,8 @@ class WorkflowRunService:
params={
"tenant_id": app_model.tenant_id,
"app_id": app_model.id,
"workflow_id": workflow_run.workflow_id,
"triggered_from": workflow_run.triggered_from,
"session_factory": db.session.get_bind(),
}
)

View File

@@ -13,6 +13,7 @@ from core.app.apps.workflow.app_config_manager import WorkflowAppConfigManager
from core.model_runtime.utils.encoders import jsonable_encoder
from core.repository import RepositoryFactory
from core.variables import Variable
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.errors import WorkflowNodeRunFailedError
from core.workflow.graph_engine.entities.event import InNodeEvent
@@ -32,7 +33,6 @@ from models.tools import WorkflowToolProvider
from models.workflow import (
Workflow,
WorkflowNodeExecution,
WorkflowNodeExecutionStatus,
WorkflowNodeExecutionTriggeredFrom,
WorkflowType,
)
@@ -289,6 +289,10 @@ class WorkflowService:
params={
"tenant_id": app_model.tenant_id,
"app_id": app_model.id,
"workflow_id": draft_workflow.id,
"triggered_from": workflow_node_execution.triggered_from,
"created_by_role": workflow_node_execution.created_by_role,
"created_by": workflow_node_execution.created_by,
"session_factory": db.session.get_bind(),
}
)
@@ -388,7 +392,7 @@ class WorkflowService:
workflow_node_execution = WorkflowNodeExecution()
workflow_node_execution.id = str(uuid4())
workflow_node_execution.tenant_id = tenant_id
workflow_node_execution.triggered_from = WorkflowNodeExecutionTriggeredFrom.SINGLE_STEP.value
workflow_node_execution.triggered_from = WorkflowNodeExecutionTriggeredFrom.SINGLE_STEP
workflow_node_execution.index = 1
workflow_node_execution.node_id = node_id
workflow_node_execution.node_type = node_instance.node_type

View File

@@ -6,6 +6,7 @@ from typing import cast
import pytest
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
@@ -15,7 +16,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime
from core.workflow.nodes.code.code_node import CodeNode
from core.workflow.nodes.code.entities import CodeNodeData
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_code_executor_mock
CODE_MAX_STRING_LENGTH = int(getenv("CODE_MAX_STRING_LENGTH", "10000"))

View File

@@ -8,6 +8,7 @@ from unittest.mock import MagicMock
import pytest
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
from core.workflow.graph_engine.entities.graph import Graph
@@ -17,7 +18,7 @@ from core.workflow.nodes.event import RunCompletedEvent
from core.workflow.nodes.llm.node import LLMNode
from extensions.ext_database import db
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
from tests.integration_tests.workflow.nodes.__mock.model import get_mocked_fetch_model_config
"""FOR MOCK FIXTURES, DO NOT REMOVE"""

View File

@@ -4,6 +4,7 @@ import uuid
import pytest
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
from core.workflow.graph_engine.entities.graph import Graph
@@ -11,7 +12,7 @@ from core.workflow.graph_engine.entities.graph_init_params import GraphInitParam
from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState
from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_code_executor_mock

View File

@@ -4,6 +4,7 @@ from unittest.mock import MagicMock
from core.app.entities.app_invoke_entities import InvokeFrom
from core.tools.utils.configuration import ToolParameterConfigurationManager
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
from core.workflow.graph_engine.entities.graph import Graph
@@ -12,7 +13,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime
from core.workflow.nodes.event.event import RunCompletedEvent
from core.workflow.nodes.tool.tool_node import ToolNode
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
def init_tool_node(config: dict):

View File

@@ -4,6 +4,7 @@ import pytest
from flask import Flask
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
@@ -25,7 +26,7 @@ from core.workflow.nodes.event import RunCompletedEvent, RunStreamChunkEvent
from core.workflow.nodes.llm.node import LLMNode
from core.workflow.nodes.question_classifier.question_classifier_node import QuestionClassifierNode
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
@pytest.fixture

View File

@@ -3,6 +3,7 @@ import uuid
from unittest.mock import MagicMock
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
from core.workflow.graph_engine.entities.graph import Graph
@@ -11,7 +12,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime
from core.workflow.nodes.answer.answer_node import AnswerNode
from extensions.ext_database import db
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
def test_execute_answer():

View File

@@ -3,6 +3,7 @@ import httpx
from core.app.entities.app_invoke_entities import InvokeFrom
from core.file import File, FileTransferMethod, FileType
from core.variables import ArrayFileVariable, FileVariable
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState
from core.workflow.nodes.answer import AnswerStreamGenerateRoute
@@ -15,7 +16,7 @@ from core.workflow.nodes.http_request import (
HttpRequestNodeData,
)
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
def test_http_request_node_binary_file(monkeypatch):

View File

@@ -3,6 +3,7 @@ import uuid
from unittest.mock import patch
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
@@ -14,7 +15,7 @@ from core.workflow.nodes.iteration.entities import ErrorHandleMode
from core.workflow.nodes.iteration.iteration_node import IterationNode
from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
def test_run():

View File

@@ -3,6 +3,7 @@ import uuid
from unittest.mock import MagicMock
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
from core.workflow.graph_engine.entities.graph import Graph
@@ -11,7 +12,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime
from core.workflow.nodes.answer.answer_node import AnswerNode
from extensions.ext_database import db
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
def test_execute_answer():

View File

@@ -1,6 +1,7 @@
from unittest.mock import patch
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult
from core.workflow.enums import SystemVariableKey
from core.workflow.graph_engine.entities.event import (
@@ -14,7 +15,7 @@ from core.workflow.graph_engine.graph_engine import GraphEngine
from core.workflow.nodes.event.event import RunCompletedEvent, RunStreamChunkEvent
from core.workflow.nodes.llm.node import LLMNode
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
class ContinueOnErrorTestHelper:

View File

@@ -6,6 +6,7 @@ from docx.oxml.text.paragraph import CT_P
from core.file import File, FileTransferMethod
from core.variables import ArrayFileSegment
from core.variables.variables import StringVariable
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.nodes.document_extractor import DocumentExtractorNode, DocumentExtractorNodeData
from core.workflow.nodes.document_extractor.node import (
@@ -14,7 +15,6 @@ from core.workflow.nodes.document_extractor.node import (
_extract_text_from_plain_text,
)
from core.workflow.nodes.enums import NodeType
from models.workflow import WorkflowNodeExecutionStatus
@pytest.fixture

View File

@@ -5,6 +5,7 @@ from unittest.mock import MagicMock, Mock
from core.app.entities.app_invoke_entities import InvokeFrom
from core.file import File, FileTransferMethod, FileType
from core.variables import ArrayFileSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.enums import SystemVariableKey
from core.workflow.graph_engine.entities.graph import Graph
@@ -15,7 +16,7 @@ from core.workflow.nodes.if_else.if_else_node import IfElseNode
from core.workflow.utils.condition.entities import Condition, SubCondition, SubVariableCondition
from extensions.ext_database import db
from models.enums import UserFrom
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
from models.workflow import WorkflowType
def test_execute_if_else_result_true():

View File

@@ -4,6 +4,7 @@ import pytest
from core.file import File, FileTransferMethod, FileType
from core.variables import ArrayFileSegment
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.nodes.list_operator.entities import (
ExtractConfig,
FilterBy,
@@ -14,7 +15,6 @@ from core.workflow.nodes.list_operator.entities import (
)
from core.workflow.nodes.list_operator.exc import InvalidKeyError
from core.workflow.nodes.list_operator.node import ListOperatorNode, _get_file_extract_string_func
from models.workflow import WorkflowNodeExecutionStatus
@pytest.fixture

View File

@@ -5,6 +5,7 @@ import pytest
from core.app.entities.app_invoke_entities import InvokeFrom
from core.tools.entities.tool_entities import ToolInvokeMessage, ToolProviderType
from core.tools.errors import ToolInvokeError
from core.workflow.entities import WorkflowNodeExecutionStatus
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState
@@ -14,7 +15,7 @@ from core.workflow.nodes.enums import ErrorStrategy
from core.workflow.nodes.event import RunCompletedEvent
from core.workflow.nodes.tool import ToolNode
from core.workflow.nodes.tool.entities import ToolNodeData
from models import UserFrom, WorkflowNodeExecutionStatus, WorkflowType
from models import UserFrom, WorkflowType
def _create_tool_node():