Signed-off-by: -LAN- <laipz8200@outlook.com>tags/1.4.2
| from controllers.console import api | from controllers.console import api | ||||
| from controllers.console.app.wraps import get_app_model | from controllers.console.app.wraps import get_app_model | ||||
| from controllers.console.wraps import account_initialization_required, setup_required | from controllers.console.wraps import account_initialization_required, setup_required | ||||
| from core.workflow.entities.workflow_execution import WorkflowExecutionStatus | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from fields.workflow_app_log_fields import workflow_app_log_pagination_fields | from fields.workflow_app_log_fields import workflow_app_log_pagination_fields | ||||
| from libs.login import login_required | from libs.login import login_required | ||||
| from models import App | from models import App | ||||
| from models.model import AppMode | from models.model import AppMode | ||||
| from models.workflow import WorkflowRunStatus | |||||
| from services.workflow_app_service import WorkflowAppService | from services.workflow_app_service import WorkflowAppService | ||||
| parser.add_argument("limit", type=int_range(1, 100), default=20, location="args") | parser.add_argument("limit", type=int_range(1, 100), default=20, location="args") | ||||
| args = parser.parse_args() | args = parser.parse_args() | ||||
| args.status = WorkflowRunStatus(args.status) if args.status else None | |||||
| args.status = WorkflowExecutionStatus(args.status) if args.status else None | |||||
| if args.created_at__before: | if args.created_at__before: | ||||
| args.created_at__before = isoparse(args.created_at__before) | args.created_at__before = isoparse(args.created_at__before) | ||||
| QuotaExceededError, | QuotaExceededError, | ||||
| ) | ) | ||||
| from core.model_runtime.errors.invoke import InvokeError | from core.model_runtime.errors.invoke import InvokeError | ||||
| from core.workflow.entities.workflow_execution import WorkflowExecutionStatus | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from fields.workflow_app_log_fields import workflow_app_log_pagination_fields | from fields.workflow_app_log_fields import workflow_app_log_pagination_fields | ||||
| from libs import helper | from libs import helper | ||||
| from libs.helper import TimestampField | from libs.helper import TimestampField | ||||
| from models.model import App, AppMode, EndUser | from models.model import App, AppMode, EndUser | ||||
| from models.workflow import WorkflowRun, WorkflowRunStatus | |||||
| from models.workflow import WorkflowRun | |||||
| from services.app_generate_service import AppGenerateService | from services.app_generate_service import AppGenerateService | ||||
| from services.errors.llm import InvokeRateLimitError | from services.errors.llm import InvokeRateLimitError | ||||
| from services.workflow_app_service import WorkflowAppService | from services.workflow_app_service import WorkflowAppService | ||||
| parser.add_argument("limit", type=int_range(1, 100), default=20, location="args") | parser.add_argument("limit", type=int_range(1, 100), default=20, location="args") | ||||
| args = parser.parse_args() | args = parser.parse_args() | ||||
| args.status = WorkflowRunStatus(args.status) if args.status else None | |||||
| args.status = WorkflowExecutionStatus(args.status) if args.status else None | |||||
| if args.created_at__before: | if args.created_at__before: | ||||
| args.created_at__before = isoparse(args.created_at__before) | args.created_at__before = isoparse(args.created_at__before) | ||||
| from core.prompt.utils.get_thread_messages_length import get_thread_messages_length | from core.prompt.utils.get_thread_messages_length import get_thread_messages_length | ||||
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository | from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository | ||||
| from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from factories import file_factory | from factories import file_factory | ||||
| from models import Account, App, Conversation, EndUser, Message, Workflow, WorkflowNodeExecutionTriggeredFrom | from models import Account, App, Conversation, EndUser, Message, Workflow, WorkflowNodeExecutionTriggeredFrom |
| from core.model_runtime.entities.llm_entities import LLMUsage | from core.model_runtime.entities.llm_entities import LLMUsage | ||||
| from core.model_runtime.utils.encoders import jsonable_encoder | from core.model_runtime.utils.encoders import jsonable_encoder | ||||
| from core.ops.ops_trace_manager import TraceQueueManager | from core.ops.ops_trace_manager import TraceQueueManager | ||||
| from core.workflow.entities.workflow_execution import WorkflowExecutionStatus, WorkflowType | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState | from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState | ||||
| from core.workflow.nodes import NodeType | from core.workflow.nodes import NodeType | ||||
| from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.workflow_cycle_manager import WorkflowCycleManager | |||||
| from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.workflow_cycle_manager import CycleManagerWorkflowInfo, WorkflowCycleManager | |||||
| from events.message_event import message_was_created | from events.message_event import message_was_created | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models import Conversation, EndUser, Message, MessageFile | from models import Conversation, EndUser, Message, MessageFile | ||||
| from models.account import Account | from models.account import Account | ||||
| from models.enums import CreatorUserRole | from models.enums import CreatorUserRole | ||||
| from models.workflow import ( | |||||
| Workflow, | |||||
| WorkflowRunStatus, | |||||
| ) | |||||
| from models.workflow import Workflow | |||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||
| SystemVariableKey.WORKFLOW_ID: workflow.id, | SystemVariableKey.WORKFLOW_ID: workflow.id, | ||||
| SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_run_id, | SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_run_id, | ||||
| }, | }, | ||||
| workflow_info=CycleManagerWorkflowInfo( | |||||
| workflow_id=workflow.id, | |||||
| workflow_type=WorkflowType(workflow.type), | |||||
| version=workflow.version, | |||||
| graph_data=workflow.graph_dict, | |||||
| ), | |||||
| workflow_execution_repository=workflow_execution_repository, | workflow_execution_repository=workflow_execution_repository, | ||||
| workflow_node_execution_repository=workflow_node_execution_repository, | workflow_node_execution_repository=workflow_node_execution_repository, | ||||
| ) | ) | ||||
| with Session(db.engine, expire_on_commit=False) as session: | with Session(db.engine, expire_on_commit=False) as session: | ||||
| # init workflow run | # init workflow run | ||||
| workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start( | |||||
| session=session, | |||||
| workflow_id=self._workflow_id, | |||||
| ) | |||||
| self._workflow_run_id = workflow_execution.id | |||||
| workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start() | |||||
| self._workflow_run_id = workflow_execution.id_ | |||||
| message = self._get_message(session=session) | message = self._get_message(session=session) | ||||
| if not message: | if not message: | ||||
| raise ValueError(f"Message not found: {self._message_id}") | raise ValueError(f"Message not found: {self._message_id}") | ||||
| message.workflow_run_id = workflow_execution.id | |||||
| message.workflow_run_id = workflow_execution.id_ | |||||
| workflow_start_resp = self._workflow_response_converter.workflow_start_to_stream_response( | workflow_start_resp = self._workflow_response_converter.workflow_start_to_stream_response( | ||||
| task_id=self._application_generate_entity.task_id, | task_id=self._application_generate_entity.task_id, | ||||
| workflow_execution=workflow_execution, | workflow_execution=workflow_execution, | ||||
| workflow_run_id=self._workflow_run_id, | workflow_run_id=self._workflow_run_id, | ||||
| total_tokens=graph_runtime_state.total_tokens, | total_tokens=graph_runtime_state.total_tokens, | ||||
| total_steps=graph_runtime_state.node_run_steps, | total_steps=graph_runtime_state.node_run_steps, | ||||
| status=WorkflowRunStatus.FAILED, | |||||
| status=WorkflowExecutionStatus.FAILED, | |||||
| error_message=event.error, | error_message=event.error, | ||||
| conversation_id=self._conversation_id, | conversation_id=self._conversation_id, | ||||
| trace_manager=trace_manager, | trace_manager=trace_manager, | ||||
| workflow_run_id=self._workflow_run_id, | workflow_run_id=self._workflow_run_id, | ||||
| total_tokens=graph_runtime_state.total_tokens, | total_tokens=graph_runtime_state.total_tokens, | ||||
| total_steps=graph_runtime_state.node_run_steps, | total_steps=graph_runtime_state.node_run_steps, | ||||
| status=WorkflowRunStatus.STOPPED, | |||||
| status=WorkflowExecutionStatus.STOPPED, | |||||
| error_message=event.get_stop_reason(), | error_message=event.get_stop_reason(), | ||||
| conversation_id=self._conversation_id, | conversation_id=self._conversation_id, | ||||
| trace_manager=trace_manager, | trace_manager=trace_manager, |
| ) | ) | ||||
| from core.file import FILE_MODEL_IDENTITY, File | from core.file import FILE_MODEL_IDENTITY, File | ||||
| from core.tools.tool_manager import ToolManager | from core.tools.tool_manager import ToolManager | ||||
| from core.workflow.entities.node_execution_entities import NodeExecution | |||||
| from core.workflow.entities.workflow_execution_entities import WorkflowExecution | |||||
| from core.workflow.entities.workflow_execution import WorkflowExecution | |||||
| from core.workflow.entities.workflow_node_execution import NodeExecution, WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes import NodeType | from core.workflow.nodes import NodeType | ||||
| from core.workflow.nodes.tool.entities import ToolNodeData | from core.workflow.nodes.tool.entities import ToolNodeData | ||||
| from models import ( | from models import ( | ||||
| Account, | Account, | ||||
| CreatorUserRole, | CreatorUserRole, | ||||
| EndUser, | EndUser, | ||||
| WorkflowNodeExecutionStatus, | |||||
| WorkflowRun, | WorkflowRun, | ||||
| ) | ) | ||||
| ) -> WorkflowStartStreamResponse: | ) -> WorkflowStartStreamResponse: | ||||
| return WorkflowStartStreamResponse( | return WorkflowStartStreamResponse( | ||||
| task_id=task_id, | task_id=task_id, | ||||
| workflow_run_id=workflow_execution.id, | |||||
| workflow_run_id=workflow_execution.id_, | |||||
| data=WorkflowStartStreamResponse.Data( | data=WorkflowStartStreamResponse.Data( | ||||
| id=workflow_execution.id, | |||||
| id=workflow_execution.id_, | |||||
| workflow_id=workflow_execution.workflow_id, | workflow_id=workflow_execution.workflow_id, | ||||
| sequence_number=workflow_execution.sequence_number, | |||||
| inputs=workflow_execution.inputs, | inputs=workflow_execution.inputs, | ||||
| created_at=int(workflow_execution.started_at.timestamp()), | created_at=int(workflow_execution.started_at.timestamp()), | ||||
| ), | ), | ||||
| workflow_execution: WorkflowExecution, | workflow_execution: WorkflowExecution, | ||||
| ) -> WorkflowFinishStreamResponse: | ) -> WorkflowFinishStreamResponse: | ||||
| created_by = None | created_by = None | ||||
| workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id)) | |||||
| workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id_)) | |||||
| assert workflow_run is not None | assert workflow_run is not None | ||||
| if workflow_run.created_by_role == CreatorUserRole.ACCOUNT: | if workflow_run.created_by_role == CreatorUserRole.ACCOUNT: | ||||
| stmt = select(Account).where(Account.id == workflow_run.created_by) | stmt = select(Account).where(Account.id == workflow_run.created_by) | ||||
| return WorkflowFinishStreamResponse( | return WorkflowFinishStreamResponse( | ||||
| task_id=task_id, | task_id=task_id, | ||||
| workflow_run_id=workflow_execution.id, | |||||
| workflow_run_id=workflow_execution.id_, | |||||
| data=WorkflowFinishStreamResponse.Data( | data=WorkflowFinishStreamResponse.Data( | ||||
| id=workflow_execution.id, | |||||
| id=workflow_execution.id_, | |||||
| workflow_id=workflow_execution.workflow_id, | workflow_id=workflow_execution.workflow_id, | ||||
| sequence_number=workflow_execution.sequence_number, | |||||
| status=workflow_execution.status, | status=workflow_execution.status, | ||||
| outputs=workflow_execution.outputs, | outputs=workflow_execution.outputs, | ||||
| error=workflow_execution.error_message, | error=workflow_execution.error_message, |
| from core.ops.ops_trace_manager import TraceQueueManager | from core.ops.ops_trace_manager import TraceQueueManager | ||||
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository | from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository | ||||
| from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from factories import file_factory | from factories import file_factory | ||||
| from models import Account, App, EndUser, Workflow, WorkflowNodeExecutionTriggeredFrom | from models import Account, App, EndUser, Workflow, WorkflowNodeExecutionTriggeredFrom | ||||
| invoke_from=invoke_from, | invoke_from=invoke_from, | ||||
| call_depth=call_depth, | call_depth=call_depth, | ||||
| trace_manager=trace_manager, | trace_manager=trace_manager, | ||||
| workflow_run_id=workflow_run_id, | |||||
| workflow_execution_id=workflow_run_id, | |||||
| ) | ) | ||||
| contexts.plugin_tool_providers.set({}) | contexts.plugin_tool_providers.set({}) | ||||
| single_iteration_run=WorkflowAppGenerateEntity.SingleIterationRunEntity( | single_iteration_run=WorkflowAppGenerateEntity.SingleIterationRunEntity( | ||||
| node_id=node_id, inputs=args["inputs"] | node_id=node_id, inputs=args["inputs"] | ||||
| ), | ), | ||||
| workflow_run_id=str(uuid.uuid4()), | |||||
| workflow_execution_id=str(uuid.uuid4()), | |||||
| ) | ) | ||||
| contexts.plugin_tool_providers.set({}) | contexts.plugin_tool_providers.set({}) | ||||
| contexts.plugin_tool_providers_lock.set(threading.Lock()) | contexts.plugin_tool_providers_lock.set(threading.Lock()) | ||||
| invoke_from=InvokeFrom.DEBUGGER, | invoke_from=InvokeFrom.DEBUGGER, | ||||
| extras={"auto_generate_conversation_name": False}, | extras={"auto_generate_conversation_name": False}, | ||||
| single_loop_run=WorkflowAppGenerateEntity.SingleLoopRunEntity(node_id=node_id, inputs=args["inputs"]), | single_loop_run=WorkflowAppGenerateEntity.SingleLoopRunEntity(node_id=node_id, inputs=args["inputs"]), | ||||
| workflow_run_id=str(uuid.uuid4()), | |||||
| workflow_execution_id=str(uuid.uuid4()), | |||||
| ) | ) | ||||
| contexts.plugin_tool_providers.set({}) | contexts.plugin_tool_providers.set({}) | ||||
| contexts.plugin_tool_providers_lock.set(threading.Lock()) | contexts.plugin_tool_providers_lock.set(threading.Lock()) |
| SystemVariableKey.USER_ID: user_id, | SystemVariableKey.USER_ID: user_id, | ||||
| SystemVariableKey.APP_ID: app_config.app_id, | SystemVariableKey.APP_ID: app_config.app_id, | ||||
| SystemVariableKey.WORKFLOW_ID: app_config.workflow_id, | SystemVariableKey.WORKFLOW_ID: app_config.workflow_id, | ||||
| SystemVariableKey.WORKFLOW_RUN_ID: self.application_generate_entity.workflow_run_id, | |||||
| SystemVariableKey.WORKFLOW_RUN_ID: self.application_generate_entity.workflow_execution_id, | |||||
| } | } | ||||
| variable_pool = VariablePool( | variable_pool = VariablePool( |
| from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline | from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline | ||||
| from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk | from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk | ||||
| from core.ops.ops_trace_manager import TraceQueueManager | from core.ops.ops_trace_manager import TraceQueueManager | ||||
| from core.workflow.entities.workflow_execution_entities import WorkflowExecution | |||||
| from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.workflow_cycle_manager import WorkflowCycleManager | |||||
| from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.workflow_cycle_manager import CycleManagerWorkflowInfo, WorkflowCycleManager | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.account import Account | from models.account import Account | ||||
| from models.enums import CreatorUserRole | from models.enums import CreatorUserRole | ||||
| WorkflowAppLog, | WorkflowAppLog, | ||||
| WorkflowAppLogCreatedFrom, | WorkflowAppLogCreatedFrom, | ||||
| WorkflowRun, | WorkflowRun, | ||||
| WorkflowRunStatus, | |||||
| ) | ) | ||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||
| SystemVariableKey.USER_ID: user_session_id, | SystemVariableKey.USER_ID: user_session_id, | ||||
| SystemVariableKey.APP_ID: application_generate_entity.app_config.app_id, | SystemVariableKey.APP_ID: application_generate_entity.app_config.app_id, | ||||
| SystemVariableKey.WORKFLOW_ID: workflow.id, | SystemVariableKey.WORKFLOW_ID: workflow.id, | ||||
| SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_run_id, | |||||
| SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_execution_id, | |||||
| }, | }, | ||||
| workflow_info=CycleManagerWorkflowInfo( | |||||
| workflow_id=workflow.id, | |||||
| workflow_type=WorkflowType(workflow.type), | |||||
| version=workflow.version, | |||||
| graph_data=workflow.graph_dict, | |||||
| ), | |||||
| workflow_execution_repository=workflow_execution_repository, | workflow_execution_repository=workflow_execution_repository, | ||||
| workflow_node_execution_repository=workflow_node_execution_repository, | workflow_node_execution_repository=workflow_node_execution_repository, | ||||
| ) | ) | ||||
| # override graph runtime state | # override graph runtime state | ||||
| graph_runtime_state = event.graph_runtime_state | graph_runtime_state = event.graph_runtime_state | ||||
| with Session(db.engine, expire_on_commit=False) as session: | |||||
| # init workflow run | |||||
| workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start( | |||||
| session=session, | |||||
| workflow_id=self._workflow_id, | |||||
| ) | |||||
| self._workflow_run_id = workflow_execution.id | |||||
| start_resp = self._workflow_response_converter.workflow_start_to_stream_response( | |||||
| task_id=self._application_generate_entity.task_id, | |||||
| workflow_execution=workflow_execution, | |||||
| ) | |||||
| # init workflow run | |||||
| workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start() | |||||
| self._workflow_run_id = workflow_execution.id_ | |||||
| start_resp = self._workflow_response_converter.workflow_start_to_stream_response( | |||||
| task_id=self._application_generate_entity.task_id, | |||||
| workflow_execution=workflow_execution, | |||||
| ) | |||||
| yield start_resp | yield start_resp | ||||
| elif isinstance( | elif isinstance( | ||||
| workflow_run_id=self._workflow_run_id, | workflow_run_id=self._workflow_run_id, | ||||
| total_tokens=graph_runtime_state.total_tokens, | total_tokens=graph_runtime_state.total_tokens, | ||||
| total_steps=graph_runtime_state.node_run_steps, | total_steps=graph_runtime_state.node_run_steps, | ||||
| status=WorkflowRunStatus.FAILED | |||||
| status=WorkflowExecutionStatus.FAILED | |||||
| if isinstance(event, QueueWorkflowFailedEvent) | if isinstance(event, QueueWorkflowFailedEvent) | ||||
| else WorkflowRunStatus.STOPPED, | |||||
| else WorkflowExecutionStatus.STOPPED, | |||||
| error_message=event.error | error_message=event.error | ||||
| if isinstance(event, QueueWorkflowFailedEvent) | if isinstance(event, QueueWorkflowFailedEvent) | ||||
| else event.get_stop_reason(), | else event.get_stop_reason(), | ||||
| tts_publisher.publish(None) | tts_publisher.publish(None) | ||||
| def _save_workflow_app_log(self, *, session: Session, workflow_execution: WorkflowExecution) -> None: | def _save_workflow_app_log(self, *, session: Session, workflow_execution: WorkflowExecution) -> None: | ||||
| workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id)) | |||||
| workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id_)) | |||||
| assert workflow_run is not None | assert workflow_run is not None | ||||
| invoke_from = self._application_generate_entity.invoke_from | invoke_from = self._application_generate_entity.invoke_from | ||||
| if invoke_from == InvokeFrom.SERVICE_API: | if invoke_from == InvokeFrom.SERVICE_API: |
| QueueWorkflowStartedEvent, | QueueWorkflowStartedEvent, | ||||
| QueueWorkflowSucceededEvent, | QueueWorkflowSucceededEvent, | ||||
| ) | ) | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey | |||||
| from core.workflow.graph_engine.entities.event import ( | from core.workflow.graph_engine.entities.event import ( | ||||
| AgentLogEvent, | AgentLogEvent, | ||||
| GraphEngineEvent, | GraphEngineEvent, |
| App Generate Entity. | App Generate Entity. | ||||
| """ | """ | ||||
| model_config = ConfigDict(arbitrary_types_allowed=True) | |||||
| task_id: str | task_id: str | ||||
| # app config | # app config | ||||
| # tracing instance | # tracing instance | ||||
| trace_manager: Optional[TraceQueueManager] = None | trace_manager: Optional[TraceQueueManager] = None | ||||
| class Config: | |||||
| arbitrary_types_allowed = True | |||||
| class EasyUIBasedAppGenerateEntity(AppGenerateEntity): | class EasyUIBasedAppGenerateEntity(AppGenerateEntity): | ||||
| """ | """ | ||||
| # app config | # app config | ||||
| app_config: WorkflowUIBasedAppConfig | app_config: WorkflowUIBasedAppConfig | ||||
| workflow_run_id: str | |||||
| workflow_execution_id: str | |||||
| class SingleIterationRunEntity(BaseModel): | class SingleIterationRunEntity(BaseModel): | ||||
| """ | """ |
| from pydantic import BaseModel | from pydantic import BaseModel | ||||
| from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk | from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk | ||||
| from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunMetadataKey | |||||
| from core.workflow.entities.node_entities import AgentNodeStrategyInit | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey | |||||
| from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState | from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState | ||||
| from core.workflow.nodes import NodeType | from core.workflow.nodes import NodeType | ||||
| from core.workflow.nodes.base import BaseNodeData | from core.workflow.nodes.base import BaseNodeData |
| from core.model_runtime.entities.llm_entities import LLMResult | from core.model_runtime.entities.llm_entities import LLMResult | ||||
| from core.model_runtime.utils.encoders import jsonable_encoder | from core.model_runtime.utils.encoders import jsonable_encoder | ||||
| from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunMetadataKey | |||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from core.workflow.entities.node_entities import AgentNodeStrategyInit | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| class TaskState(BaseModel): | class TaskState(BaseModel): | ||||
| id: str | id: str | ||||
| workflow_id: str | workflow_id: str | ||||
| sequence_number: int | |||||
| inputs: Mapping[str, Any] | inputs: Mapping[str, Any] | ||||
| created_at: int | created_at: int | ||||
| id: str | id: str | ||||
| workflow_id: str | workflow_id: str | ||||
| sequence_number: int | |||||
| status: str | status: str | ||||
| outputs: Optional[Mapping[str, Any]] = None | outputs: Optional[Mapping[str, Any]] = None | ||||
| error: Optional[str] = None | error: Optional[str] = None |
| from enum import StrEnum | from enum import StrEnum | ||||
| from typing import Any, Optional, Union | from typing import Any, Optional, Union | ||||
| from pydantic import BaseModel, ConfigDict, field_validator | |||||
| from pydantic import BaseModel, ConfigDict, field_serializer, field_validator | |||||
| class BaseTraceInfo(BaseModel): | class BaseTraceInfo(BaseModel): | ||||
| return v | return v | ||||
| return "" | return "" | ||||
| class Config: | |||||
| json_encoders = { | |||||
| datetime: lambda v: v.isoformat(), | |||||
| } | |||||
| model_config = ConfigDict(protected_namespaces=()) | |||||
| @field_serializer("start_time", "end_time") | |||||
| def serialize_datetime(self, dt: datetime | None) -> str | None: | |||||
| if dt is None: | |||||
| return None | |||||
| return dt.isoformat() | |||||
| class WorkflowTraceInfo(BaseTraceInfo): | class WorkflowTraceInfo(BaseTraceInfo): |
| ) | ) | ||||
| from core.ops.utils import filter_none_values, generate_dotted_order | from core.ops.utils import filter_none_values, generate_dotted_order | ||||
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom | from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom |
| WorkflowTraceInfo, | WorkflowTraceInfo, | ||||
| ) | ) | ||||
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom | from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom |
| WorkflowTraceInfo, | WorkflowTraceInfo, | ||||
| ) | ) | ||||
| from core.ops.utils import get_message_data | from core.ops.utils import get_message_data | ||||
| from core.workflow.entities.workflow_execution_entities import WorkflowExecution | |||||
| from core.workflow.entities.workflow_execution import WorkflowExecution | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from extensions.ext_storage import storage | from extensions.ext_storage import storage | ||||
| from models.model import App, AppModelConfig, Conversation, Message, MessageFile, TraceAppConfig | from models.model import App, AppModelConfig, Conversation, Message, MessageFile, TraceAppConfig | ||||
| ): | ): | ||||
| self.trace_type = trace_type | self.trace_type = trace_type | ||||
| self.message_id = message_id | self.message_id = message_id | ||||
| self.workflow_run_id = workflow_execution.id if workflow_execution else None | |||||
| self.workflow_run_id = workflow_execution.id_ if workflow_execution else None | |||||
| self.conversation_id = conversation_id | self.conversation_id = conversation_id | ||||
| self.user_id = user_id | self.user_id = user_id | ||||
| self.timer = timer | self.timer = timer |
| ) | ) | ||||
| from core.ops.weave_trace.entities.weave_trace_entity import WeaveTraceModel | from core.ops.weave_trace.entities.weave_trace_entity import WeaveTraceModel | ||||
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom | from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom |
| website import info. | website import info. | ||||
| """ | """ | ||||
| model_config = ConfigDict(arbitrary_types_allowed=True) | |||||
| provider: str | provider: str | ||||
| job_id: str | job_id: str | ||||
| url: str | url: str | ||||
| tenant_id: str | tenant_id: str | ||||
| only_main_content: bool = False | only_main_content: bool = False | ||||
| class Config: | |||||
| arbitrary_types_allowed = True | |||||
| def __init__(self, **data) -> None: | |||||
| super().__init__(**data) | |||||
| class ExtractSetting(BaseModel): | class ExtractSetting(BaseModel): | ||||
| """ | """ |
| .. code-block:: python | .. code-block:: python | ||||
| class EmbeddingsRedundantFilter(BaseDocumentTransformer, BaseModel): | class EmbeddingsRedundantFilter(BaseDocumentTransformer, BaseModel): | ||||
| model_config = ConfigDict(arbitrary_types_allowed=True) | |||||
| embeddings: Embeddings | embeddings: Embeddings | ||||
| similarity_fn: Callable = cosine_similarity | similarity_fn: Callable = cosine_similarity | ||||
| similarity_threshold: float = 0.95 | similarity_threshold: float = 0.95 | ||||
| class Config: | |||||
| arbitrary_types_allowed = True | |||||
| def transform_documents( | def transform_documents( | ||||
| self, documents: Sequence[Document], **kwargs: Any | self, documents: Sequence[Document], **kwargs: Any | ||||
| ) -> Sequence[Document]: | ) -> Sequence[Document]: |
| from sqlalchemy.engine import Engine | from sqlalchemy.engine import Engine | ||||
| from sqlalchemy.orm import sessionmaker | from sqlalchemy.orm import sessionmaker | ||||
| from core.workflow.entities.workflow_execution_entities import ( | |||||
| from core.workflow.entities.workflow_execution import ( | |||||
| WorkflowExecution, | WorkflowExecution, | ||||
| WorkflowExecutionStatus, | WorkflowExecutionStatus, | ||||
| WorkflowType, | WorkflowType, | ||||
| ) | ) | ||||
| from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from models import ( | from models import ( | ||||
| Account, | Account, | ||||
| CreatorUserRole, | CreatorUserRole, | ||||
| status = WorkflowExecutionStatus(db_model.status) | status = WorkflowExecutionStatus(db_model.status) | ||||
| return WorkflowExecution( | return WorkflowExecution( | ||||
| id=db_model.id, | |||||
| id_=db_model.id, | |||||
| workflow_id=db_model.workflow_id, | workflow_id=db_model.workflow_id, | ||||
| sequence_number=db_model.sequence_number, | |||||
| type=WorkflowType(db_model.type), | |||||
| workflow_type=WorkflowType(db_model.type), | |||||
| workflow_version=db_model.version, | workflow_version=db_model.version, | ||||
| graph=graph, | graph=graph, | ||||
| inputs=inputs, | inputs=inputs, | ||||
| raise ValueError("created_by_role is required in repository constructor") | raise ValueError("created_by_role is required in repository constructor") | ||||
| db_model = WorkflowRun() | db_model = WorkflowRun() | ||||
| db_model.id = domain_model.id | |||||
| db_model.id = domain_model.id_ | |||||
| db_model.tenant_id = self._tenant_id | db_model.tenant_id = self._tenant_id | ||||
| if self._app_id is not None: | if self._app_id is not None: | ||||
| db_model.app_id = self._app_id | db_model.app_id = self._app_id | ||||
| db_model.workflow_id = domain_model.workflow_id | db_model.workflow_id = domain_model.workflow_id | ||||
| db_model.triggered_from = self._triggered_from | db_model.triggered_from = self._triggered_from | ||||
| db_model.sequence_number = domain_model.sequence_number | |||||
| db_model.type = domain_model.type | |||||
| # Check if this is a new record | |||||
| with self._session_factory() as session: | |||||
| existing = session.scalar(select(WorkflowRun).where(WorkflowRun.id == domain_model.id_)) | |||||
| if not existing: | |||||
| # For new records, get the next sequence number | |||||
| stmt = select(WorkflowRun.sequence_number).where( | |||||
| WorkflowRun.app_id == self._app_id, | |||||
| WorkflowRun.tenant_id == self._tenant_id, | |||||
| ) | |||||
| max_sequence = session.scalar(stmt.order_by(WorkflowRun.sequence_number.desc())) | |||||
| db_model.sequence_number = (max_sequence or 0) + 1 | |||||
| else: | |||||
| # For updates, keep the existing sequence number | |||||
| db_model.sequence_number = existing.sequence_number | |||||
| db_model.type = domain_model.workflow_type | |||||
| db_model.version = domain_model.workflow_version | db_model.version = domain_model.workflow_version | ||||
| db_model.graph = json.dumps(domain_model.graph) if domain_model.graph else None | db_model.graph = json.dumps(domain_model.graph) if domain_model.graph else None | ||||
| db_model.inputs = json.dumps(domain_model.inputs) if domain_model.inputs else None | db_model.inputs = json.dumps(domain_model.inputs) if domain_model.inputs else None |
| from sqlalchemy.orm import sessionmaker | from sqlalchemy.orm import sessionmaker | ||||
| from core.model_runtime.utils.encoders import jsonable_encoder | from core.model_runtime.utils.encoders import jsonable_encoder | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.node_execution_entities import ( | |||||
| from core.workflow.entities.workflow_node_execution import ( | |||||
| NodeExecution, | NodeExecution, | ||||
| NodeExecutionStatus, | |||||
| NodeRunMetadataKey, | |||||
| WorkflowNodeExecutionStatus, | |||||
| ) | ) | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.repository.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository | |||||
| from models import ( | from models import ( | ||||
| Account, | Account, | ||||
| CreatorUserRole, | CreatorUserRole, | ||||
| EndUser, | EndUser, | ||||
| WorkflowNodeExecution, | WorkflowNodeExecution, | ||||
| WorkflowNodeExecutionStatus, | |||||
| WorkflowNodeExecutionTriggeredFrom, | WorkflowNodeExecutionTriggeredFrom, | ||||
| ) | ) | ||||
| metadata = {NodeRunMetadataKey(k): v for k, v in db_model.execution_metadata_dict.items()} | metadata = {NodeRunMetadataKey(k): v for k, v in db_model.execution_metadata_dict.items()} | ||||
| # Convert status to domain enum | # Convert status to domain enum | ||||
| status = NodeExecutionStatus(db_model.status) | |||||
| status = WorkflowNodeExecutionStatus(db_model.status) | |||||
| return NodeExecution( | return NodeExecution( | ||||
| id=db_model.id, | id=db_model.id, |
| from collections.abc import Mapping | from collections.abc import Mapping | ||||
| from enum import StrEnum | |||||
| from typing import Any, Optional | from typing import Any, Optional | ||||
| from pydantic import BaseModel | from pydantic import BaseModel | ||||
| from core.model_runtime.entities.llm_entities import LLMUsage | from core.model_runtime.entities.llm_entities import LLMUsage | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class NodeRunMetadataKey(StrEnum): | |||||
| """ | |||||
| Node Run Metadata Key. | |||||
| """ | |||||
| TOTAL_TOKENS = "total_tokens" | |||||
| TOTAL_PRICE = "total_price" | |||||
| CURRENCY = "currency" | |||||
| TOOL_INFO = "tool_info" | |||||
| AGENT_LOG = "agent_log" | |||||
| ITERATION_ID = "iteration_id" | |||||
| ITERATION_INDEX = "iteration_index" | |||||
| LOOP_ID = "loop_id" | |||||
| LOOP_INDEX = "loop_index" | |||||
| PARALLEL_ID = "parallel_id" | |||||
| PARALLEL_START_NODE_ID = "parallel_start_node_id" | |||||
| PARENT_PARALLEL_ID = "parent_parallel_id" | |||||
| PARENT_PARALLEL_START_NODE_ID = "parent_parallel_start_node_id" | |||||
| PARALLEL_MODE_RUN_ID = "parallel_mode_run_id" | |||||
| ITERATION_DURATION_MAP = "iteration_duration_map" # single iteration duration if iteration node runs | |||||
| LOOP_DURATION_MAP = "loop_duration_map" # single loop duration if loop node runs | |||||
| ERROR_STRATEGY = "error_strategy" # node in continue on error mode return the field | |||||
| LOOP_VARIABLE_MAP = "loop_variable_map" # single loop variable output | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| class NodeRunResult(BaseModel): | class NodeRunResult(BaseModel): |
| user, tenant, and app attributes. | user, tenant, and app attributes. | ||||
| """ | """ | ||||
| id: str = Field(...) | |||||
| id_: str = Field(...) | |||||
| workflow_id: str = Field(...) | workflow_id: str = Field(...) | ||||
| workflow_version: str = Field(...) | workflow_version: str = Field(...) | ||||
| sequence_number: int = Field(...) | |||||
| type: WorkflowType = Field(...) | |||||
| workflow_type: WorkflowType = Field(...) | |||||
| graph: Mapping[str, Any] = Field(...) | graph: Mapping[str, Any] = Field(...) | ||||
| inputs: Mapping[str, Any] = Field(...) | inputs: Mapping[str, Any] = Field(...) | ||||
| def new( | def new( | ||||
| cls, | cls, | ||||
| *, | *, | ||||
| id: str, | |||||
| id_: str, | |||||
| workflow_id: str, | workflow_id: str, | ||||
| sequence_number: int, | |||||
| type: WorkflowType, | |||||
| workflow_type: WorkflowType, | |||||
| workflow_version: str, | workflow_version: str, | ||||
| graph: Mapping[str, Any], | graph: Mapping[str, Any], | ||||
| inputs: Mapping[str, Any], | inputs: Mapping[str, Any], | ||||
| started_at: datetime, | started_at: datetime, | ||||
| ) -> "WorkflowExecution": | ) -> "WorkflowExecution": | ||||
| return WorkflowExecution( | return WorkflowExecution( | ||||
| id=id, | |||||
| id_=id_, | |||||
| workflow_id=workflow_id, | workflow_id=workflow_id, | ||||
| sequence_number=sequence_number, | |||||
| type=type, | |||||
| workflow_type=workflow_type, | |||||
| workflow_version=workflow_version, | workflow_version=workflow_version, | ||||
| graph=graph, | graph=graph, | ||||
| inputs=inputs, | inputs=inputs, |
| from pydantic import BaseModel, Field | from pydantic import BaseModel, Field | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| class NodeExecutionStatus(StrEnum): | |||||
| class NodeRunMetadataKey(StrEnum): | |||||
| """ | |||||
| Node Run Metadata Key. | |||||
| """ | |||||
| TOTAL_TOKENS = "total_tokens" | |||||
| TOTAL_PRICE = "total_price" | |||||
| CURRENCY = "currency" | |||||
| TOOL_INFO = "tool_info" | |||||
| AGENT_LOG = "agent_log" | |||||
| ITERATION_ID = "iteration_id" | |||||
| ITERATION_INDEX = "iteration_index" | |||||
| LOOP_ID = "loop_id" | |||||
| LOOP_INDEX = "loop_index" | |||||
| PARALLEL_ID = "parallel_id" | |||||
| PARALLEL_START_NODE_ID = "parallel_start_node_id" | |||||
| PARENT_PARALLEL_ID = "parent_parallel_id" | |||||
| PARENT_PARALLEL_START_NODE_ID = "parent_parallel_start_node_id" | |||||
| PARALLEL_MODE_RUN_ID = "parallel_mode_run_id" | |||||
| ITERATION_DURATION_MAP = "iteration_duration_map" # single iteration duration if iteration node runs | |||||
| LOOP_DURATION_MAP = "loop_duration_map" # single loop duration if loop node runs | |||||
| ERROR_STRATEGY = "error_strategy" # node in continue on error mode return the field | |||||
| LOOP_VARIABLE_MAP = "loop_variable_map" # single loop variable output | |||||
| class WorkflowNodeExecutionStatus(StrEnum): | |||||
| """ | """ | ||||
| Node Execution Status Enum. | Node Execution Status Enum. | ||||
| """ | """ | ||||
| outputs: Optional[Mapping[str, Any]] = None # Output variables produced by this node | outputs: Optional[Mapping[str, Any]] = None # Output variables produced by this node | ||||
| # Execution state | # Execution state | ||||
| status: NodeExecutionStatus = NodeExecutionStatus.RUNNING # Current execution status | |||||
| status: WorkflowNodeExecutionStatus = WorkflowNodeExecutionStatus.RUNNING # Current execution status | |||||
| error: Optional[str] = None # Error message if execution failed | error: Optional[str] = None # Error message if execution failed | ||||
| elapsed_time: float = Field(default=0.0) # Time taken for execution in seconds | elapsed_time: float = Field(default=0.0) # Time taken for execution in seconds | ||||
| from pydantic import BaseModel, Field | from pydantic import BaseModel, Field | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| class RouteNodeState(BaseModel): | class RouteNodeState(BaseModel): |
| from configs import dify_config | from configs import dify_config | ||||
| from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError | from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError | ||||
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunMetadataKey, NodeRunResult | |||||
| from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunResult | |||||
| from core.workflow.entities.variable_pool import VariablePool, VariableValue | from core.workflow.entities.variable_pool import VariablePool, VariableValue | ||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| from core.workflow.graph_engine.condition_handlers.condition_manager import ConditionManager | from core.workflow.graph_engine.condition_handlers.condition_manager import ConditionManager | ||||
| from core.workflow.graph_engine.entities.event import ( | from core.workflow.graph_engine.entities.event import ( | ||||
| BaseAgentEvent, | BaseAgentEvent, | ||||
| from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING | from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||
| from core.variables.segments import StringSegment | from core.variables.segments import StringSegment | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.nodes.agent.entities import AgentNodeData, AgentOldVersionModelFeatures, ParamsAutoGenerated | from core.workflow.nodes.agent.entities import AgentNodeData, AgentOldVersionModelFeatures, ParamsAutoGenerated | ||||
| from core.workflow.nodes.base.entities import BaseNodeData | from core.workflow.nodes.base.entities import BaseNodeData | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from factories.agent_factory import get_plugin_agent_strategy | from factories.agent_factory import get_plugin_agent_strategy | ||||
| from models.model import Conversation | from models.model import Conversation | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class AgentNode(ToolNode): | class AgentNode(ToolNode): |
| from core.variables import ArrayFileSegment, FileSegment | from core.variables import ArrayFileSegment, FileSegment | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.answer.answer_stream_generate_router import AnswerStreamGeneratorRouter | from core.workflow.nodes.answer.answer_stream_generate_router import AnswerStreamGeneratorRouter | ||||
| from core.workflow.nodes.answer.entities import ( | from core.workflow.nodes.answer.entities import ( | ||||
| AnswerNodeData, | AnswerNodeData, | ||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.utils.variable_template_parser import VariableTemplateParser | from core.workflow.utils.variable_template_parser import VariableTemplateParser | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class AnswerNode(BaseNode[AnswerNodeData]): | class AnswerNode(BaseNode[AnswerNodeData]): |
| from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast | from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.enums import CONTINUE_ON_ERROR_NODE_TYPE, RETRY_ON_ERROR_NODE_TYPE, NodeType | 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 core.workflow.nodes.event import NodeEvent, RunCompletedEvent | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .entities import BaseNodeData | from .entities import BaseNodeData | ||||
| from core.helper.code_executor.python3.python3_code_provider import Python3CodeProvider | from core.helper.code_executor.python3.python3_code_provider import Python3CodeProvider | ||||
| from core.variables.segments import ArrayFileSegment | from core.variables.segments import ArrayFileSegment | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.code.entities import CodeNodeData | from core.workflow.nodes.code.entities import CodeNodeData | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .exc import ( | from .exc import ( | ||||
| CodeNodeError, | CodeNodeError, |
| from core.variables import ArrayFileSegment | from core.variables import ArrayFileSegment | ||||
| from core.variables.segments import FileSegment | from core.variables.segments import FileSegment | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .entities import DocumentExtractorNodeData | from .entities import DocumentExtractorNodeData | ||||
| from .exc import DocumentExtractorError, FileDownloadError, TextExtractionError, UnsupportedFileTypeError | from .exc import DocumentExtractorError, FileDownloadError, TextExtractionError, UnsupportedFileTypeError |
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.end.entities import EndNodeData | from core.workflow.nodes.end.entities import EndNodeData | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class EndNode(BaseNode[EndNodeData]): | class EndNode(BaseNode[EndNodeData]): |
| from core.model_runtime.entities.llm_entities import LLMUsage | from core.model_runtime.entities.llm_entities import LLMUsage | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| class RunCompletedEvent(BaseModel): | class RunCompletedEvent(BaseModel): |
| from core.tools.tool_file_manager import ToolFileManager | from core.tools.tool_file_manager import ToolFileManager | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.variable_entities import VariableSelector | from core.workflow.entities.variable_entities import VariableSelector | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.http_request.executor import Executor | from core.workflow.nodes.http_request.executor import Executor | ||||
| from core.workflow.utils import variable_template_parser | from core.workflow.utils import variable_template_parser | ||||
| from factories import file_factory | from factories import file_factory | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .entities import ( | from .entities import ( | ||||
| HttpRequestNodeData, | HttpRequestNodeData, |
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.if_else.entities import IfElseNodeData | from core.workflow.nodes.if_else.entities import IfElseNodeData | ||||
| from core.workflow.utils.condition.entities import Condition | from core.workflow.utils.condition.entities import Condition | ||||
| from core.workflow.utils.condition.processor import ConditionProcessor | from core.workflow.utils.condition.processor import ConditionProcessor | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class IfElseNode(BaseNode[IfElseNodeData]): | class IfElseNode(BaseNode[IfElseNodeData]): |
| from configs import dify_config | from configs import dify_config | ||||
| from core.variables import ArrayVariable, IntegerVariable, NoneVariable | from core.variables import ArrayVariable, IntegerVariable, NoneVariable | ||||
| from core.workflow.entities.node_entities import ( | from core.workflow.entities.node_entities import ( | ||||
| NodeRunMetadataKey, | |||||
| NodeRunResult, | NodeRunResult, | ||||
| ) | ) | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| from core.workflow.graph_engine.entities.event import ( | from core.workflow.graph_engine.entities.event import ( | ||||
| BaseGraphEvent, | BaseGraphEvent, | ||||
| BaseNodeEvent, | BaseNodeEvent, | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.event import NodeEvent, RunCompletedEvent | from core.workflow.nodes.event import NodeEvent, RunCompletedEvent | ||||
| from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData | from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .exc import ( | from .exc import ( | ||||
| InvalidIteratorValueError, | InvalidIteratorValueError, |
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.iteration.entities import IterationStartNodeData | from core.workflow.nodes.iteration.entities import IterationStartNodeData | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class IterationStartNode(BaseNode[IterationStartNodeData]): | class IterationStartNode(BaseNode[IterationStartNodeData]): |
| from core.rag.retrieval.retrieval_methods import RetrievalMethod | from core.rag.retrieval.retrieval_methods import RetrievalMethod | ||||
| from core.variables import StringSegment | from core.variables import StringSegment | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.event.event import ModelInvokeCompletedEvent | from core.workflow.nodes.event.event import ModelInvokeCompletedEvent | ||||
| from core.workflow.nodes.knowledge_retrieval.template_prompts import ( | from core.workflow.nodes.knowledge_retrieval.template_prompts import ( | ||||
| from extensions.ext_redis import redis_client | from extensions.ext_redis import redis_client | ||||
| from libs.json_in_md_parser import parse_and_check_json_markdown | from libs.json_in_md_parser import parse_and_check_json_markdown | ||||
| from models.dataset import Dataset, DatasetMetadata, Document, RateLimitLog | from models.dataset import Dataset, DatasetMetadata, Document, RateLimitLog | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from services.feature_service import FeatureService | from services.feature_service import FeatureService | ||||
| from .entities import KnowledgeRetrievalNodeData, ModelConfig | from .entities import KnowledgeRetrievalNodeData, ModelConfig |
| from core.file import File | from core.file import File | ||||
| from core.variables import ArrayFileSegment, ArrayNumberSegment, ArrayStringSegment | from core.variables import ArrayFileSegment, ArrayNumberSegment, ArrayStringSegment | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .entities import ListOperatorNodeData | from .entities import ListOperatorNodeData | ||||
| from .exc import InvalidConditionError, InvalidFilterValueError, InvalidKeyError, ListOperatorError | from .exc import InvalidConditionError, InvalidFilterValueError, InvalidKeyError, ListOperatorError |
| StringSegment, | StringSegment, | ||||
| ) | ) | ||||
| from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID | from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | |||||
| from core.workflow.entities.node_entities import NodeRunResult | |||||
| from core.workflow.entities.variable_entities import VariableSelector | from core.workflow.entities.variable_entities import VariableSelector | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.event import InNodeEvent | from core.workflow.graph_engine.entities.event import InNodeEvent | ||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.model import Conversation | from models.model import Conversation | ||||
| from models.provider import Provider, ProviderType | from models.provider import Provider, ProviderType | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .entities import ( | from .entities import ( | ||||
| LLMNodeChatModelMessage, | LLMNodeChatModelMessage, |
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.loop.entities import LoopEndNodeData | from core.workflow.nodes.loop.entities import LoopEndNodeData | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class LoopEndNode(BaseNode[LoopEndNodeData]): | class LoopEndNode(BaseNode[LoopEndNodeData]): |
| SegmentType, | SegmentType, | ||||
| StringSegment, | StringSegment, | ||||
| ) | ) | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | |||||
| from core.workflow.entities.node_entities import NodeRunResult | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| from core.workflow.graph_engine.entities.event import ( | from core.workflow.graph_engine.entities.event import ( | ||||
| BaseGraphEvent, | BaseGraphEvent, | ||||
| BaseNodeEvent, | BaseNodeEvent, | ||||
| from core.workflow.nodes.event import NodeEvent, RunCompletedEvent | from core.workflow.nodes.event import NodeEvent, RunCompletedEvent | ||||
| from core.workflow.nodes.loop.entities import LoopNodeData | from core.workflow.nodes.loop.entities import LoopNodeData | ||||
| from core.workflow.utils.condition.processor import ConditionProcessor | from core.workflow.utils.condition.processor import ConditionProcessor | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool |
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.loop.entities import LoopStartNodeData | from core.workflow.nodes.loop.entities import LoopStartNodeData | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class LoopStartNode(BaseNode[LoopStartNodeData]): | class LoopStartNode(BaseNode[LoopStartNodeData]): |
| from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate | from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate | ||||
| from core.prompt.simple_prompt_transform import ModelMode | from core.prompt.simple_prompt_transform import ModelMode | ||||
| from core.prompt.utils.prompt_message_util import PromptMessageUtil | from core.prompt.utils.prompt_message_util import PromptMessageUtil | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | |||||
| from core.workflow.entities.node_entities import NodeRunResult | |||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.llm import LLMNode, ModelConfig | from core.workflow.nodes.llm import LLMNode, ModelConfig | ||||
| from core.workflow.utils import variable_template_parser | from core.workflow.utils import variable_template_parser | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .entities import ParameterExtractorNodeData | from .entities import ParameterExtractorNodeData | ||||
| from .exc import ( | from .exc import ( |
| from core.prompt.advanced_prompt_transform import AdvancedPromptTransform | from core.prompt.advanced_prompt_transform import AdvancedPromptTransform | ||||
| from core.prompt.simple_prompt_transform import ModelMode | from core.prompt.simple_prompt_transform import ModelMode | ||||
| from core.prompt.utils.prompt_message_util import PromptMessageUtil | from core.prompt.utils.prompt_message_util import PromptMessageUtil | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | |||||
| from core.workflow.entities.node_entities import NodeRunResult | |||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.event import ModelInvokeCompletedEvent | from core.workflow.nodes.event import ModelInvokeCompletedEvent | ||||
| from core.workflow.nodes.llm import ( | from core.workflow.nodes.llm import ( | ||||
| ) | ) | ||||
| from core.workflow.utils.variable_template_parser import VariableTemplateParser | from core.workflow.utils.variable_template_parser import VariableTemplateParser | ||||
| from libs.json_in_md_parser import parse_and_check_json_markdown | from libs.json_in_md_parser import parse_and_check_json_markdown | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .entities import QuestionClassifierNodeData | from .entities import QuestionClassifierNodeData | ||||
| from .exc import InvalidModelTypeError | from .exc import InvalidModelTypeError |
| from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID | from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.start.entities import StartNodeData | from core.workflow.nodes.start.entities import StartNodeData | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class StartNode(BaseNode[StartNodeData]): | class StartNode(BaseNode[StartNodeData]): |
| from core.helper.code_executor.code_executor import CodeExecutionError, CodeExecutor, CodeLanguage | from core.helper.code_executor.code_executor import CodeExecutionError, CodeExecutor, CodeLanguage | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.template_transform.entities import TemplateTransformNodeData | 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")) | MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH = int(os.environ.get("TEMPLATE_TRANSFORM_MAX_LENGTH", "80000")) | ||||
| from core.tools.utils.message_transformer import ToolFileMessageTransformer | from core.tools.utils.message_transformer import ToolFileMessageTransformer | ||||
| from core.variables.segments import ArrayAnySegment | from core.variables.segments import ArrayAnySegment | ||||
| from core.variables.variables import ArrayAnyVariable | from core.variables.variables import ArrayAnyVariable | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | |||||
| from core.workflow.entities.node_entities import NodeRunResult | |||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.event import AgentLogEvent | from core.workflow.graph_engine.entities.event import AgentLogEvent | ||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from factories import file_factory | from factories import file_factory | ||||
| from models import ToolFile | from models import ToolFile | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from services.tools.builtin_tools_manage_service import BuiltinToolManageService | from services.tools.builtin_tools_manage_service import BuiltinToolManageService | ||||
| from .entities import ToolNodeData | from .entities import ToolNodeData |
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.nodes.variable_aggregator.entities import VariableAssignerNodeData | from core.workflow.nodes.variable_aggregator.entities import VariableAssignerNodeData | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| class VariableAggregatorNode(BaseNode[VariableAssignerNodeData]): | class VariableAggregatorNode(BaseNode[VariableAssignerNodeData]): |
| from core.variables import SegmentType, Variable | from core.variables import SegmentType, Variable | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | 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 import helpers as common_helpers | ||||
| from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError | from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError | ||||
| from factories import variable_factory | from factories import variable_factory | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from .node_data import VariableAssignerData, WriteMode | from .node_data import VariableAssignerData, WriteMode | ||||
| from core.variables import SegmentType, Variable | from core.variables import SegmentType, Variable | ||||
| from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID | from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.base import BaseNode | from core.workflow.nodes.base import BaseNode | ||||
| from core.workflow.nodes.enums import NodeType | 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 import helpers as common_helpers | ||||
| from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError | from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| from . import helpers | from . import helpers | ||||
| from .constants import EMPTY_VALUE_MAPPING | from .constants import EMPTY_VALUE_MAPPING |
| storage mechanism. | storage mechanism. | ||||
| """ | """ | ||||
| from core.workflow.repository.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository | |||||
| __all__ = [ | __all__ = [ | ||||
| "OrderConfig", | "OrderConfig", |
| from typing import Optional, Protocol | from typing import Optional, Protocol | ||||
| from core.workflow.entities.workflow_execution_entities import WorkflowExecution | |||||
| from core.workflow.entities.workflow_execution import WorkflowExecution | |||||
| class WorkflowExecutionRepository(Protocol): | class WorkflowExecutionRepository(Protocol): |
| from dataclasses import dataclass | from dataclasses import dataclass | ||||
| from typing import Literal, Optional, Protocol | from typing import Literal, Optional, Protocol | ||||
| from core.workflow.entities.node_execution_entities import NodeExecution | |||||
| from core.workflow.entities.workflow_node_execution import NodeExecution | |||||
| @dataclass | @dataclass |
| from collections.abc import Mapping | from collections.abc import Mapping | ||||
| from dataclasses import dataclass | |||||
| from datetime import UTC, datetime | from datetime import UTC, datetime | ||||
| from typing import Any, Optional, Union | from typing import Any, Optional, Union | ||||
| from uuid import uuid4 | from uuid import uuid4 | ||||
| from sqlalchemy import func, select | |||||
| from sqlalchemy.orm import Session | |||||
| from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity | from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity | ||||
| from core.app.entities.queue_entities import ( | from core.app.entities.queue_entities import ( | ||||
| QueueNodeExceptionEvent, | QueueNodeExceptionEvent, | ||||
| from core.app.task_pipeline.exc import WorkflowRunNotFoundError | from core.app.task_pipeline.exc import WorkflowRunNotFoundError | ||||
| from core.ops.entities.trace_entity import TraceTaskName | from core.ops.entities.trace_entity import TraceTaskName | ||||
| from core.ops.ops_trace_manager import TraceQueueManager, TraceTask | from core.ops.ops_trace_manager import TraceQueueManager, TraceTask | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.node_execution_entities import ( | |||||
| from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType | |||||
| from core.workflow.entities.workflow_node_execution import ( | |||||
| NodeExecution, | NodeExecution, | ||||
| NodeExecutionStatus, | |||||
| NodeRunMetadataKey, | |||||
| WorkflowNodeExecutionStatus, | |||||
| ) | ) | ||||
| from core.workflow.entities.workflow_execution_entities import WorkflowExecution, WorkflowExecutionStatus, WorkflowType | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.workflow_entry import WorkflowEntry | from core.workflow.workflow_entry import WorkflowEntry | ||||
| from models import ( | |||||
| Workflow, | |||||
| WorkflowRun, | |||||
| WorkflowRunStatus, | |||||
| ) | |||||
| @dataclass | |||||
| class CycleManagerWorkflowInfo: | |||||
| workflow_id: str | |||||
| workflow_type: WorkflowType | |||||
| version: str | |||||
| graph_data: Mapping[str, Any] | |||||
| class WorkflowCycleManager: | class WorkflowCycleManager: | ||||
| *, | *, | ||||
| application_generate_entity: Union[AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity], | application_generate_entity: Union[AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity], | ||||
| workflow_system_variables: dict[SystemVariableKey, Any], | workflow_system_variables: dict[SystemVariableKey, Any], | ||||
| workflow_info: CycleManagerWorkflowInfo, | |||||
| workflow_execution_repository: WorkflowExecutionRepository, | workflow_execution_repository: WorkflowExecutionRepository, | ||||
| workflow_node_execution_repository: WorkflowNodeExecutionRepository, | workflow_node_execution_repository: WorkflowNodeExecutionRepository, | ||||
| ) -> None: | ) -> None: | ||||
| self._application_generate_entity = application_generate_entity | self._application_generate_entity = application_generate_entity | ||||
| self._workflow_system_variables = workflow_system_variables | self._workflow_system_variables = workflow_system_variables | ||||
| self._workflow_info = workflow_info | |||||
| self._workflow_execution_repository = workflow_execution_repository | self._workflow_execution_repository = workflow_execution_repository | ||||
| self._workflow_node_execution_repository = workflow_node_execution_repository | self._workflow_node_execution_repository = workflow_node_execution_repository | ||||
| def handle_workflow_run_start( | |||||
| self, | |||||
| *, | |||||
| session: Session, | |||||
| workflow_id: str, | |||||
| ) -> WorkflowExecution: | |||||
| workflow_stmt = select(Workflow).where(Workflow.id == workflow_id) | |||||
| workflow = session.scalar(workflow_stmt) | |||||
| if not workflow: | |||||
| raise ValueError(f"Workflow not found: {workflow_id}") | |||||
| max_sequence_stmt = select(func.max(WorkflowRun.sequence_number)).where( | |||||
| WorkflowRun.tenant_id == workflow.tenant_id, | |||||
| WorkflowRun.app_id == workflow.app_id, | |||||
| ) | |||||
| max_sequence = session.scalar(max_sequence_stmt) or 0 | |||||
| new_sequence_number = max_sequence + 1 | |||||
| def handle_workflow_run_start(self) -> WorkflowExecution: | |||||
| inputs = {**self._application_generate_entity.inputs} | inputs = {**self._application_generate_entity.inputs} | ||||
| for key, value in (self._workflow_system_variables or {}).items(): | for key, value in (self._workflow_system_variables or {}).items(): | ||||
| if key.value == "conversation": | if key.value == "conversation": | ||||
| # TODO: This workflow_run_id should always not be None, maybe we can use a more elegant way to handle this | # TODO: This workflow_run_id should always not be None, maybe we can use a more elegant way to handle this | ||||
| execution_id = str(self._workflow_system_variables.get(SystemVariableKey.WORKFLOW_RUN_ID) or uuid4()) | execution_id = str(self._workflow_system_variables.get(SystemVariableKey.WORKFLOW_RUN_ID) or uuid4()) | ||||
| execution = WorkflowExecution.new( | execution = WorkflowExecution.new( | ||||
| id=execution_id, | |||||
| workflow_id=workflow.id, | |||||
| sequence_number=new_sequence_number, | |||||
| type=WorkflowType(workflow.type), | |||||
| workflow_version=workflow.version, | |||||
| graph=workflow.graph_dict, | |||||
| id_=execution_id, | |||||
| workflow_id=self._workflow_info.workflow_id, | |||||
| workflow_type=self._workflow_info.workflow_type, | |||||
| workflow_version=self._workflow_info.version, | |||||
| graph=self._workflow_info.graph_data, | |||||
| inputs=inputs, | inputs=inputs, | ||||
| started_at=datetime.now(UTC).replace(tzinfo=None), | started_at=datetime.now(UTC).replace(tzinfo=None), | ||||
| ) | ) | ||||
| workflow_run_id: str, | workflow_run_id: str, | ||||
| total_tokens: int, | total_tokens: int, | ||||
| total_steps: int, | total_steps: int, | ||||
| status: WorkflowRunStatus, | |||||
| status: WorkflowExecutionStatus, | |||||
| error_message: str, | error_message: str, | ||||
| conversation_id: Optional[str] = None, | conversation_id: Optional[str] = None, | ||||
| trace_manager: Optional[TraceQueueManager] = None, | trace_manager: Optional[TraceQueueManager] = None, | ||||
| # Use the instance repository to find running executions for a workflow run | # Use the instance repository to find running executions for a workflow run | ||||
| running_node_executions = self._workflow_node_execution_repository.get_running_executions( | running_node_executions = self._workflow_node_execution_repository.get_running_executions( | ||||
| workflow_run_id=workflow_execution.id | |||||
| workflow_run_id=workflow_execution.id_ | |||||
| ) | ) | ||||
| # Update the domain models | # Update the domain models | ||||
| for node_execution in running_node_executions: | for node_execution in running_node_executions: | ||||
| if node_execution.node_execution_id: | if node_execution.node_execution_id: | ||||
| # Update the domain model | # Update the domain model | ||||
| node_execution.status = NodeExecutionStatus.FAILED | |||||
| node_execution.status = WorkflowNodeExecutionStatus.FAILED | |||||
| node_execution.error = error_message | node_execution.error = error_message | ||||
| node_execution.finished_at = now | node_execution.finished_at = now | ||||
| node_execution.elapsed_time = (now - node_execution.created_at).total_seconds() | node_execution.elapsed_time = (now - node_execution.created_at).total_seconds() | ||||
| domain_execution = NodeExecution( | domain_execution = NodeExecution( | ||||
| id=str(uuid4()), | id=str(uuid4()), | ||||
| workflow_id=workflow_execution.workflow_id, | workflow_id=workflow_execution.workflow_id, | ||||
| workflow_run_id=workflow_execution.id, | |||||
| workflow_run_id=workflow_execution.id_, | |||||
| predecessor_node_id=event.predecessor_node_id, | predecessor_node_id=event.predecessor_node_id, | ||||
| index=event.node_run_index, | index=event.node_run_index, | ||||
| node_execution_id=event.node_execution_id, | node_execution_id=event.node_execution_id, | ||||
| node_id=event.node_id, | node_id=event.node_id, | ||||
| node_type=event.node_type, | node_type=event.node_type, | ||||
| title=event.node_data.title, | title=event.node_data.title, | ||||
| status=NodeExecutionStatus.RUNNING, | |||||
| status=WorkflowNodeExecutionStatus.RUNNING, | |||||
| metadata=metadata, | metadata=metadata, | ||||
| created_at=created_at, | created_at=created_at, | ||||
| ) | ) | ||||
| elapsed_time = (finished_at - event.start_at).total_seconds() | elapsed_time = (finished_at - event.start_at).total_seconds() | ||||
| # Update domain model | # Update domain model | ||||
| domain_execution.status = NodeExecutionStatus.SUCCEEDED | |||||
| domain_execution.status = WorkflowNodeExecutionStatus.SUCCEEDED | |||||
| domain_execution.update_from_mapping( | domain_execution.update_from_mapping( | ||||
| inputs=inputs, process_data=process_data, outputs=outputs, metadata=execution_metadata_dict | inputs=inputs, process_data=process_data, outputs=outputs, metadata=execution_metadata_dict | ||||
| ) | ) | ||||
| # Update domain model | # Update domain model | ||||
| domain_execution.status = ( | domain_execution.status = ( | ||||
| NodeExecutionStatus.FAILED | |||||
| WorkflowNodeExecutionStatus.FAILED | |||||
| if not isinstance(event, QueueNodeExceptionEvent) | if not isinstance(event, QueueNodeExceptionEvent) | ||||
| else NodeExecutionStatus.EXCEPTION | |||||
| else WorkflowNodeExecutionStatus.EXCEPTION | |||||
| ) | ) | ||||
| domain_execution.error = event.error | domain_execution.error = event.error | ||||
| domain_execution.update_from_mapping( | domain_execution.update_from_mapping( | ||||
| domain_execution = NodeExecution( | domain_execution = NodeExecution( | ||||
| id=str(uuid4()), | id=str(uuid4()), | ||||
| workflow_id=workflow_execution.workflow_id, | workflow_id=workflow_execution.workflow_id, | ||||
| workflow_run_id=workflow_execution.id, | |||||
| workflow_run_id=workflow_execution.id_, | |||||
| predecessor_node_id=event.predecessor_node_id, | predecessor_node_id=event.predecessor_node_id, | ||||
| node_execution_id=event.node_execution_id, | node_execution_id=event.node_execution_id, | ||||
| node_id=event.node_id, | node_id=event.node_id, | ||||
| node_type=event.node_type, | node_type=event.node_type, | ||||
| title=event.node_data.title, | title=event.node_data.title, | ||||
| status=NodeExecutionStatus.RETRY, | |||||
| status=WorkflowNodeExecutionStatus.RETRY, | |||||
| created_at=created_at, | created_at=created_at, | ||||
| finished_at=finished_at, | finished_at=finished_at, | ||||
| elapsed_time=elapsed_time, | elapsed_time=elapsed_time, |
| WorkflowAppLog, | WorkflowAppLog, | ||||
| WorkflowAppLogCreatedFrom, | WorkflowAppLogCreatedFrom, | ||||
| WorkflowNodeExecution, | WorkflowNodeExecution, | ||||
| WorkflowNodeExecutionStatus, | |||||
| WorkflowNodeExecutionTriggeredFrom, | WorkflowNodeExecutionTriggeredFrom, | ||||
| WorkflowRun, | WorkflowRun, | ||||
| WorkflowRunStatus, | |||||
| WorkflowType, | WorkflowType, | ||||
| ) | ) | ||||
| "AccountStatus", | "AccountStatus", | ||||
| "ApiRequest", | "ApiRequest", | ||||
| "ApiToken", | "ApiToken", | ||||
| "ApiToolProvider", # Added | |||||
| "ApiToolProvider", | |||||
| "App", | "App", | ||||
| "AppAnnotationHitHistory", | "AppAnnotationHitHistory", | ||||
| "AppAnnotationSetting", | "AppAnnotationSetting", | ||||
| "AppDatasetJoin", | "AppDatasetJoin", | ||||
| "AppMode", | "AppMode", | ||||
| "AppModelConfig", | "AppModelConfig", | ||||
| "BuiltinToolProvider", # Added | |||||
| "BuiltinToolProvider", | |||||
| "CeleryTask", | "CeleryTask", | ||||
| "CeleryTaskSet", | "CeleryTaskSet", | ||||
| "Conversation", | "Conversation", | ||||
| "WorkflowAppLog", | "WorkflowAppLog", | ||||
| "WorkflowAppLogCreatedFrom", | "WorkflowAppLogCreatedFrom", | ||||
| "WorkflowNodeExecution", | "WorkflowNodeExecution", | ||||
| "WorkflowNodeExecutionStatus", | |||||
| "WorkflowNodeExecutionTriggeredFrom", | "WorkflowNodeExecutionTriggeredFrom", | ||||
| "WorkflowRun", | "WorkflowRun", | ||||
| "WorkflowRunStatus", | |||||
| "WorkflowRunTriggeredFrom", | "WorkflowRunTriggeredFrom", | ||||
| "WorkflowToolProvider", | "WorkflowToolProvider", | ||||
| "WorkflowType", | "WorkflowType", |
| from core.plugin.entities.plugin import GenericProviderID | from core.plugin.entities.plugin import GenericProviderID | ||||
| from core.tools.entities.tool_entities import ToolProviderType | from core.tools.entities.tool_entities import ToolProviderType | ||||
| from core.tools.signature import sign_tool_file | from core.tools.signature import sign_tool_file | ||||
| from core.workflow.entities.workflow_execution import WorkflowExecutionStatus | |||||
| from services.plugin.plugin_service import PluginService | from services.plugin.plugin_service import PluginService | ||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||
| from .engine import db | from .engine import db | ||||
| from .enums import CreatorUserRole | from .enums import CreatorUserRole | ||||
| from .types import StringUUID | from .types import StringUUID | ||||
| from .workflow import WorkflowRunStatus | |||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||
| from .workflow import Workflow | from .workflow import Workflow | ||||
| def status_count(self): | def status_count(self): | ||||
| messages = db.session.query(Message).filter(Message.conversation_id == self.id).all() | messages = db.session.query(Message).filter(Message.conversation_id == self.id).all() | ||||
| status_counts = { | status_counts = { | ||||
| WorkflowRunStatus.RUNNING: 0, | |||||
| WorkflowRunStatus.SUCCEEDED: 0, | |||||
| WorkflowRunStatus.FAILED: 0, | |||||
| WorkflowRunStatus.STOPPED: 0, | |||||
| WorkflowRunStatus.PARTIAL_SUCCEEDED: 0, | |||||
| WorkflowExecutionStatus.RUNNING: 0, | |||||
| WorkflowExecutionStatus.SUCCEEDED: 0, | |||||
| WorkflowExecutionStatus.FAILED: 0, | |||||
| WorkflowExecutionStatus.STOPPED: 0, | |||||
| WorkflowExecutionStatus.PARTIAL_SUCCEEDED: 0, | |||||
| } | } | ||||
| for message in messages: | for message in messages: | ||||
| if message.workflow_run: | if message.workflow_run: | ||||
| status_counts[WorkflowRunStatus(message.workflow_run.status)] += 1 | |||||
| status_counts[WorkflowExecutionStatus(message.workflow_run.status)] += 1 | |||||
| return ( | return ( | ||||
| { | { | ||||
| "success": status_counts[WorkflowRunStatus.SUCCEEDED], | |||||
| "failed": status_counts[WorkflowRunStatus.FAILED], | |||||
| "partial_success": status_counts[WorkflowRunStatus.PARTIAL_SUCCEEDED], | |||||
| "success": status_counts[WorkflowExecutionStatus.SUCCEEDED], | |||||
| "failed": status_counts[WorkflowExecutionStatus.FAILED], | |||||
| "partial_success": status_counts[WorkflowExecutionStatus.PARTIAL_SUCCEEDED], | |||||
| } | } | ||||
| if messages | if messages | ||||
| else None | else None |
| ) | ) | ||||
| class WorkflowRunStatus(StrEnum): | |||||
| """ | |||||
| Workflow Run Status Enum | |||||
| """ | |||||
| RUNNING = "running" | |||||
| SUCCEEDED = "succeeded" | |||||
| FAILED = "failed" | |||||
| STOPPED = "stopped" | |||||
| PARTIAL_SUCCEEDED = "partial-succeeded" | |||||
| class WorkflowRun(Base): | class WorkflowRun(Base): | ||||
| """ | """ | ||||
| Workflow Run | Workflow Run | ||||
| WORKFLOW_RUN = "workflow-run" | 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): | class WorkflowNodeExecution(Base): | ||||
| """ | """ | ||||
| Workflow Node Execution | Workflow Node Execution |
| [pytest] | [pytest] | ||||
| continue-on-collection-errors = true | |||||
| addopts = --cov=./api --cov-report=json --cov-report=xml | addopts = --cov=./api --cov-report=json --cov-report=xml | ||||
| env = | env = | ||||
| ANTHROPIC_API_KEY = sk-ant-api11-IamNotARealKeyJustForMockTestKawaiiiiiiiiii-NotBaka-ASkksz | ANTHROPIC_API_KEY = sk-ant-api11-IamNotARealKeyJustForMockTestKawaiiiiiiiiii-NotBaka-ASkksz |
| from sqlalchemy import and_, func, or_, select | from sqlalchemy import and_, func, or_, select | ||||
| from sqlalchemy.orm import Session | from sqlalchemy.orm import Session | ||||
| from core.workflow.entities.workflow_execution import WorkflowExecutionStatus | |||||
| from models import App, EndUser, WorkflowAppLog, WorkflowRun | from models import App, EndUser, WorkflowAppLog, WorkflowRun | ||||
| from models.enums import CreatorUserRole | from models.enums import CreatorUserRole | ||||
| from models.workflow import WorkflowRunStatus | |||||
| class WorkflowAppService: | class WorkflowAppService: | ||||
| session: Session, | session: Session, | ||||
| app_model: App, | app_model: App, | ||||
| keyword: str | None = None, | keyword: str | None = None, | ||||
| status: WorkflowRunStatus | None = None, | |||||
| status: WorkflowExecutionStatus | None = None, | |||||
| created_at_before: datetime | None = None, | created_at_before: datetime | None = None, | ||||
| created_at_after: datetime | None = None, | created_at_after: datetime | None = None, | ||||
| page: int = 1, | page: int = 1, |
| import contexts | import contexts | ||||
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.workflow.repository.workflow_node_execution_repository import OrderConfig | |||||
| from core.workflow.repositories.workflow_node_execution_repository import OrderConfig | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from libs.infinite_scroll_pagination import InfiniteScrollPagination | from libs.infinite_scroll_pagination import InfiniteScrollPagination | ||||
| from models import ( | from models import ( |
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.variables import Variable | from core.variables import Variable | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus | |||||
| from core.workflow.entities.workflow_node_execution import NodeExecution, WorkflowNodeExecutionStatus | |||||
| from core.workflow.errors import WorkflowNodeRunFailedError | from core.workflow.errors import WorkflowNodeRunFailedError | ||||
| from core.workflow.graph_engine.entities.event import InNodeEvent | from core.workflow.graph_engine.entities.event import InNodeEvent | ||||
| from core.workflow.nodes import NodeType | from core.workflow.nodes import NodeType | ||||
| from models.workflow import ( | from models.workflow import ( | ||||
| Workflow, | Workflow, | ||||
| WorkflowNodeExecution, | WorkflowNodeExecution, | ||||
| WorkflowNodeExecutionStatus, | |||||
| WorkflowNodeExecutionTriggeredFrom, | WorkflowNodeExecutionTriggeredFrom, | ||||
| WorkflowType, | WorkflowType, | ||||
| ) | ) | ||||
| # Map status from WorkflowNodeExecutionStatus to NodeExecutionStatus | # Map status from WorkflowNodeExecutionStatus to NodeExecutionStatus | ||||
| if node_run_result.status == WorkflowNodeExecutionStatus.SUCCEEDED: | if node_run_result.status == WorkflowNodeExecutionStatus.SUCCEEDED: | ||||
| node_execution.status = NodeExecutionStatus.SUCCEEDED | |||||
| node_execution.status = WorkflowNodeExecutionStatus.SUCCEEDED | |||||
| elif node_run_result.status == WorkflowNodeExecutionStatus.EXCEPTION: | elif node_run_result.status == WorkflowNodeExecutionStatus.EXCEPTION: | ||||
| node_execution.status = NodeExecutionStatus.EXCEPTION | |||||
| node_execution.status = WorkflowNodeExecutionStatus.EXCEPTION | |||||
| node_execution.error = node_run_result.error | node_execution.error = node_run_result.error | ||||
| else: | else: | ||||
| # Set failed status and error | # Set failed status and error | ||||
| node_execution.status = NodeExecutionStatus.FAILED | |||||
| node_execution.status = WorkflowNodeExecutionStatus.FAILED | |||||
| node_execution.error = error | node_execution.error = error | ||||
| return node_execution | return node_execution |
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.nodes.code.code_node import CodeNode | from core.workflow.nodes.code.code_node import CodeNode | ||||
| from core.workflow.nodes.code.entities import CodeNodeData | from core.workflow.nodes.code.entities import CodeNodeData | ||||
| from models.enums import UserFrom | 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 | 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")) | CODE_MAX_STRING_LENGTH = int(getenv("CODE_MAX_STRING_LENGTH", "10000")) |
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.nodes.llm.node import LLMNode | from core.workflow.nodes.llm.node import LLMNode | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.enums import UserFrom | 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 | from tests.integration_tests.workflow.nodes.__mock.model import get_mocked_fetch_model_config | ||||
| """FOR MOCK FIXTURES, DO NOT REMOVE""" | """FOR MOCK FIXTURES, DO NOT REMOVE""" |
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.model_runtime.entities import AssistantPromptMessage | from core.model_runtime.entities import AssistantPromptMessage | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from tests.integration_tests.workflow.nodes.__mock.model import get_mocked_fetch_model_config | from tests.integration_tests.workflow.nodes.__mock.model import get_mocked_fetch_model_config | ||||
| """FOR MOCK FIXTURES, DO NOT REMOVE""" | """FOR MOCK FIXTURES, DO NOT REMOVE""" | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| from tests.integration_tests.model_runtime.__mock.plugin_daemon import setup_model_mock | from tests.integration_tests.model_runtime.__mock.plugin_daemon import setup_model_mock | ||||
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState | from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState | ||||
| from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode | from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode | ||||
| from models.enums import UserFrom | 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 | from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_code_executor_mock | ||||
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.tools.utils.configuration import ToolParameterConfigurationManager | from core.tools.utils.configuration import ToolParameterConfigurationManager | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.nodes.event.event import RunCompletedEvent | from core.workflow.nodes.event.event import RunCompletedEvent | ||||
| from core.workflow.nodes.tool.tool_node import ToolNode | from core.workflow.nodes.tool.tool_node import ToolNode | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| def init_tool_node(config: dict): | def init_tool_node(config: dict): |
| from core.prompt.utils.extract_thread_messages import extract_thread_messages | from core.prompt.utils.extract_thread_messages import extract_thread_messages | ||||
| class TestMessage: | |||||
| class MockMessage: | |||||
| def __init__(self, id, parent_message_id): | def __init__(self, id, parent_message_id): | ||||
| self.id = id | self.id = id | ||||
| self.parent_message_id = parent_message_id | self.parent_message_id = parent_message_id | ||||
| def test_extract_thread_messages_single_message(): | def test_extract_thread_messages_single_message(): | ||||
| messages = [TestMessage(str(uuid4()), UUID_NIL)] | |||||
| messages = [MockMessage(str(uuid4()), UUID_NIL)] | |||||
| result = extract_thread_messages(messages) | result = extract_thread_messages(messages) | ||||
| assert len(result) == 1 | assert len(result) == 1 | ||||
| assert result[0] == messages[0] | assert result[0] == messages[0] | ||||
| def test_extract_thread_messages_linear_thread(): | def test_extract_thread_messages_linear_thread(): | ||||
| id1, id2, id3, id4, id5 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | id1, id2, id3, id4, id5 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | ||||
| messages = [ | messages = [ | ||||
| TestMessage(id5, id4), | |||||
| TestMessage(id4, id3), | |||||
| TestMessage(id3, id2), | |||||
| TestMessage(id2, id1), | |||||
| TestMessage(id1, UUID_NIL), | |||||
| MockMessage(id5, id4), | |||||
| MockMessage(id4, id3), | |||||
| MockMessage(id3, id2), | |||||
| MockMessage(id2, id1), | |||||
| MockMessage(id1, UUID_NIL), | |||||
| ] | ] | ||||
| result = extract_thread_messages(messages) | result = extract_thread_messages(messages) | ||||
| assert len(result) == 5 | assert len(result) == 5 | ||||
| def test_extract_thread_messages_branched_thread(): | def test_extract_thread_messages_branched_thread(): | ||||
| id1, id2, id3, id4 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | id1, id2, id3, id4 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | ||||
| messages = [ | messages = [ | ||||
| TestMessage(id4, id2), | |||||
| TestMessage(id3, id2), | |||||
| TestMessage(id2, id1), | |||||
| TestMessage(id1, UUID_NIL), | |||||
| MockMessage(id4, id2), | |||||
| MockMessage(id3, id2), | |||||
| MockMessage(id2, id1), | |||||
| MockMessage(id1, UUID_NIL), | |||||
| ] | ] | ||||
| result = extract_thread_messages(messages) | result = extract_thread_messages(messages) | ||||
| assert len(result) == 3 | assert len(result) == 3 | ||||
| def test_extract_thread_messages_partially_loaded(): | def test_extract_thread_messages_partially_loaded(): | ||||
| id0, id1, id2, id3 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | id0, id1, id2, id3 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | ||||
| messages = [ | messages = [ | ||||
| TestMessage(id3, id2), | |||||
| TestMessage(id2, id1), | |||||
| TestMessage(id1, id0), | |||||
| MockMessage(id3, id2), | |||||
| MockMessage(id2, id1), | |||||
| MockMessage(id1, id0), | |||||
| ] | ] | ||||
| result = extract_thread_messages(messages) | result = extract_thread_messages(messages) | ||||
| assert len(result) == 3 | assert len(result) == 3 | ||||
| def test_extract_thread_messages_legacy_messages(): | def test_extract_thread_messages_legacy_messages(): | ||||
| id1, id2, id3 = str(uuid4()), str(uuid4()), str(uuid4()) | id1, id2, id3 = str(uuid4()), str(uuid4()), str(uuid4()) | ||||
| messages = [ | messages = [ | ||||
| TestMessage(id3, UUID_NIL), | |||||
| TestMessage(id2, UUID_NIL), | |||||
| TestMessage(id1, UUID_NIL), | |||||
| MockMessage(id3, UUID_NIL), | |||||
| MockMessage(id2, UUID_NIL), | |||||
| MockMessage(id1, UUID_NIL), | |||||
| ] | ] | ||||
| result = extract_thread_messages(messages) | result = extract_thread_messages(messages) | ||||
| assert len(result) == 3 | assert len(result) == 3 | ||||
| def test_extract_thread_messages_mixed_with_legacy_messages(): | def test_extract_thread_messages_mixed_with_legacy_messages(): | ||||
| id1, id2, id3, id4, id5 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | id1, id2, id3, id4, id5 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) | ||||
| messages = [ | messages = [ | ||||
| TestMessage(id5, id4), | |||||
| TestMessage(id4, id2), | |||||
| TestMessage(id3, id2), | |||||
| TestMessage(id2, UUID_NIL), | |||||
| TestMessage(id1, UUID_NIL), | |||||
| MockMessage(id5, id4), | |||||
| MockMessage(id4, id2), | |||||
| MockMessage(id3, id2), | |||||
| MockMessage(id2, UUID_NIL), | |||||
| MockMessage(id1, UUID_NIL), | |||||
| ] | ] | ||||
| result = extract_thread_messages(messages) | result = extract_thread_messages(messages) | ||||
| assert len(result) == 4 | assert len(result) == 4 |
| import pytest | import pytest | ||||
| from pydantic.error_wrappers import ValidationError | |||||
| from pydantic import ValidationError | |||||
| from core.rag.datasource.vdb.milvus.milvus_vector import MilvusConfig | from core.rag.datasource.vdb.milvus.milvus_vector import MilvusConfig | ||||
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.event import ( | from core.workflow.graph_engine.entities.event import ( | ||||
| BaseNodeEvent, | BaseNodeEvent, | ||||
| from core.workflow.nodes.llm.node import LLMNode | from core.workflow.nodes.llm.node import LLMNode | ||||
| from core.workflow.nodes.question_classifier.question_classifier_node import QuestionClassifierNode | from core.workflow.nodes.question_classifier.question_classifier_node import QuestionClassifierNode | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| @pytest.fixture | @pytest.fixture |
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.nodes.answer.answer_node import AnswerNode | from core.workflow.nodes.answer.answer_node import AnswerNode | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| def test_execute_answer(): | def test_execute_answer(): |
| from core.file import File, FileTransferMethod, FileType | from core.file import File, FileTransferMethod, FileType | ||||
| from core.variables import ArrayFileVariable, FileVariable | from core.variables import ArrayFileVariable, FileVariable | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState | from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState | ||||
| from core.workflow.nodes.answer import AnswerStreamGenerateRoute | from core.workflow.nodes.answer import AnswerStreamGenerateRoute | ||||
| from core.workflow.nodes.end import EndStreamParam | from core.workflow.nodes.end import EndStreamParam | ||||
| HttpRequestNodeData, | HttpRequestNodeData, | ||||
| ) | ) | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| def test_http_request_node_binary_file(monkeypatch): | def test_http_request_node_binary_file(monkeypatch): |
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.nodes.iteration.iteration_node import IterationNode | from core.workflow.nodes.iteration.iteration_node import IterationNode | ||||
| from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode | from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| def test_run(): | def test_run(): |
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.nodes.answer.answer_node import AnswerNode | from core.workflow.nodes.answer.answer_node import AnswerNode | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| def test_execute_answer(): | def test_execute_answer(): |
| from core.app.entities.app_invoke_entities import InvokeFrom | from core.app.entities.app_invoke_entities import InvokeFrom | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.event import ( | from core.workflow.graph_engine.entities.event import ( | ||||
| GraphRunPartialSucceededEvent, | GraphRunPartialSucceededEvent, | ||||
| from core.workflow.nodes.event.event import RunCompletedEvent, RunStreamChunkEvent | from core.workflow.nodes.event.event import RunCompletedEvent, RunStreamChunkEvent | ||||
| from core.workflow.nodes.llm.node import LLMNode | from core.workflow.nodes.llm.node import LLMNode | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| class ContinueOnErrorTestHelper: | class ContinueOnErrorTestHelper: |
| from core.variables import ArrayFileSegment | from core.variables import ArrayFileSegment | ||||
| from core.variables.variables import StringVariable | from core.variables.variables import StringVariable | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.document_extractor import DocumentExtractorNode, DocumentExtractorNodeData | from core.workflow.nodes.document_extractor import DocumentExtractorNode, DocumentExtractorNodeData | ||||
| from core.workflow.nodes.document_extractor.node import ( | from core.workflow.nodes.document_extractor.node import ( | ||||
| _extract_text_from_docx, | _extract_text_from_docx, | ||||
| _extract_text_from_plain_text, | _extract_text_from_plain_text, | ||||
| ) | ) | ||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| @pytest.fixture | @pytest.fixture |
| from core.file import File, FileTransferMethod, FileType | from core.file import File, FileTransferMethod, FileType | ||||
| from core.variables import ArrayFileSegment | from core.variables import ArrayFileSegment | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.graph_engine.entities.graph import Graph | from core.workflow.graph_engine.entities.graph import Graph | ||||
| from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams | ||||
| from core.workflow.utils.condition.entities import Condition, SubCondition, SubVariableCondition | from core.workflow.utils.condition.entities import Condition, SubCondition, SubVariableCondition | ||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from models.enums import UserFrom | from models.enums import UserFrom | ||||
| from models.workflow import WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models.workflow import WorkflowType | |||||
| def test_execute_if_else_result_true(): | def test_execute_if_else_result_true(): |
| from core.file import File, FileTransferMethod, FileType | from core.file import File, FileTransferMethod, FileType | ||||
| from core.variables import ArrayFileSegment | from core.variables import ArrayFileSegment | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.nodes.list_operator.entities import ( | from core.workflow.nodes.list_operator.entities import ( | ||||
| ExtractConfig, | ExtractConfig, | ||||
| FilterBy, | FilterBy, | ||||
| ) | ) | ||||
| from core.workflow.nodes.list_operator.exc import InvalidKeyError | from core.workflow.nodes.list_operator.exc import InvalidKeyError | ||||
| from core.workflow.nodes.list_operator.node import ListOperatorNode, _get_file_extract_string_func | from core.workflow.nodes.list_operator.node import ListOperatorNode, _get_file_extract_string_func | ||||
| from models.workflow import WorkflowNodeExecutionStatus | |||||
| @pytest.fixture | @pytest.fixture |
| from core.tools.errors import ToolInvokeError | from core.tools.errors import ToolInvokeError | ||||
| from core.workflow.entities.node_entities import NodeRunResult | from core.workflow.entities.node_entities import NodeRunResult | ||||
| from core.workflow.entities.variable_pool import VariablePool | from core.workflow.entities.variable_pool import VariablePool | ||||
| from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus | |||||
| from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState | from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState | ||||
| from core.workflow.nodes.answer import AnswerStreamGenerateRoute | from core.workflow.nodes.answer import AnswerStreamGenerateRoute | ||||
| from core.workflow.nodes.end import EndStreamParam | from core.workflow.nodes.end import EndStreamParam | ||||
| from core.workflow.nodes.event import RunCompletedEvent | from core.workflow.nodes.event import RunCompletedEvent | ||||
| from core.workflow.nodes.tool import ToolNode | from core.workflow.nodes.tool import ToolNode | ||||
| from core.workflow.nodes.tool.entities import ToolNodeData | from core.workflow.nodes.tool.entities import ToolNodeData | ||||
| from models import UserFrom, WorkflowNodeExecutionStatus, WorkflowType | |||||
| from models import UserFrom, WorkflowType | |||||
| def _create_tool_node(): | def _create_tool_node(): |
| QueueNodeStartedEvent, | QueueNodeStartedEvent, | ||||
| QueueNodeSucceededEvent, | QueueNodeSucceededEvent, | ||||
| ) | ) | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus | |||||
| from core.workflow.entities.workflow_execution_entities import WorkflowExecution, WorkflowExecutionStatus, WorkflowType | |||||
| from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType | |||||
| from core.workflow.entities.workflow_node_execution import ( | |||||
| NodeExecution, | |||||
| NodeRunMetadataKey, | |||||
| WorkflowNodeExecutionStatus, | |||||
| ) | |||||
| from core.workflow.enums import SystemVariableKey | from core.workflow.enums import SystemVariableKey | ||||
| from core.workflow.nodes import NodeType | from core.workflow.nodes import NodeType | ||||
| from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.workflow_cycle_manager import WorkflowCycleManager | |||||
| from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository | |||||
| from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository | |||||
| from core.workflow.workflow_cycle_manager import CycleManagerWorkflowInfo, WorkflowCycleManager | |||||
| from models.enums import CreatorUserRole | from models.enums import CreatorUserRole | ||||
| from models.model import AppMode | from models.model import AppMode | ||||
| from models.workflow import ( | |||||
| Workflow, | |||||
| WorkflowRun, | |||||
| WorkflowRunStatus, | |||||
| ) | |||||
| from models.workflow import Workflow, WorkflowRun | |||||
| @pytest.fixture | @pytest.fixture | ||||
| return repo | return repo | ||||
| @pytest.fixture | |||||
| def real_workflow_entity(): | |||||
| return CycleManagerWorkflowInfo( | |||||
| workflow_id="test-workflow-id", # Matches ID used in other fixtures | |||||
| workflow_type=WorkflowType.CHAT, | |||||
| version="1.0.0", | |||||
| graph_data={ | |||||
| "nodes": [ | |||||
| { | |||||
| "id": "node1", | |||||
| "type": "chat", # NodeType is a string enum | |||||
| "name": "Chat Node", | |||||
| "data": {"model": "gpt-3.5-turbo", "prompt": "test prompt"}, | |||||
| } | |||||
| ], | |||||
| "edges": [], | |||||
| }, | |||||
| ) | |||||
| @pytest.fixture | @pytest.fixture | ||||
| def workflow_cycle_manager( | def workflow_cycle_manager( | ||||
| real_app_generate_entity, | real_app_generate_entity, | ||||
| real_workflow_system_variables, | real_workflow_system_variables, | ||||
| mock_workflow_execution_repository, | mock_workflow_execution_repository, | ||||
| mock_node_execution_repository, | mock_node_execution_repository, | ||||
| real_workflow_entity, | |||||
| ): | ): | ||||
| return WorkflowCycleManager( | return WorkflowCycleManager( | ||||
| application_generate_entity=real_app_generate_entity, | application_generate_entity=real_app_generate_entity, | ||||
| workflow_system_variables=real_workflow_system_variables, | workflow_system_variables=real_workflow_system_variables, | ||||
| workflow_info=real_workflow_entity, | |||||
| workflow_execution_repository=mock_workflow_execution_repository, | workflow_execution_repository=mock_workflow_execution_repository, | ||||
| workflow_node_execution_repository=mock_node_execution_repository, | workflow_node_execution_repository=mock_node_execution_repository, | ||||
| ) | ) | ||||
| workflow_run.version = "1.0" | workflow_run.version = "1.0" | ||||
| workflow_run.graph = json.dumps({"nodes": [], "edges": []}) | workflow_run.graph = json.dumps({"nodes": [], "edges": []}) | ||||
| workflow_run.inputs = json.dumps({"query": "test query"}) | workflow_run.inputs = json.dumps({"query": "test query"}) | ||||
| workflow_run.status = WorkflowRunStatus.RUNNING | |||||
| workflow_run.status = WorkflowExecutionStatus.RUNNING | |||||
| workflow_run.outputs = json.dumps({"answer": "test answer"}) | workflow_run.outputs = json.dumps({"answer": "test answer"}) | ||||
| workflow_run.created_by_role = CreatorUserRole.ACCOUNT | workflow_run.created_by_role = CreatorUserRole.ACCOUNT | ||||
| workflow_run.created_by = "test-user-id" | workflow_run.created_by = "test-user-id" | ||||
| assert workflow_cycle_manager._workflow_node_execution_repository == mock_node_execution_repository | assert workflow_cycle_manager._workflow_node_execution_repository == mock_node_execution_repository | ||||
| def test_handle_workflow_run_start(workflow_cycle_manager, mock_session, real_workflow): | |||||
| def test_handle_workflow_run_start(workflow_cycle_manager): | |||||
| """Test handle_workflow_run_start method""" | """Test handle_workflow_run_start method""" | ||||
| # Mock session.scalar to return the workflow and max sequence | |||||
| mock_session.scalar.side_effect = [real_workflow, 5] | |||||
| # Call the method | # Call the method | ||||
| workflow_execution = workflow_cycle_manager.handle_workflow_run_start( | |||||
| session=mock_session, | |||||
| workflow_id="test-workflow-id", | |||||
| ) | |||||
| workflow_execution = workflow_cycle_manager.handle_workflow_run_start() | |||||
| # Verify the result | # Verify the result | ||||
| assert workflow_execution.workflow_id == real_workflow.id | |||||
| assert workflow_execution.sequence_number == 6 # max_sequence + 1 | |||||
| assert workflow_execution.workflow_id == "test-workflow-id" | |||||
| # Verify the workflow_execution_repository.save was called | # Verify the workflow_execution_repository.save was called | ||||
| workflow_cycle_manager._workflow_execution_repository.save.assert_called_once_with(workflow_execution) | workflow_cycle_manager._workflow_execution_repository.save.assert_called_once_with(workflow_execution) | ||||
| # Create a real WorkflowExecution | # Create a real WorkflowExecution | ||||
| workflow_execution = WorkflowExecution( | workflow_execution = WorkflowExecution( | ||||
| id="test-workflow-run-id", | |||||
| id_="test-workflow-run-id", | |||||
| workflow_id="test-workflow-id", | workflow_id="test-workflow-id", | ||||
| workflow_version="1.0", | workflow_version="1.0", | ||||
| sequence_number=1, | |||||
| type=WorkflowType.CHAT, | |||||
| workflow_type=WorkflowType.CHAT, | |||||
| graph={"nodes": [], "edges": []}, | graph={"nodes": [], "edges": []}, | ||||
| inputs={"query": "test query"}, | inputs={"query": "test query"}, | ||||
| started_at=datetime.now(UTC).replace(tzinfo=None), | started_at=datetime.now(UTC).replace(tzinfo=None), | ||||
| # Create a real WorkflowExecution | # Create a real WorkflowExecution | ||||
| workflow_execution = WorkflowExecution( | workflow_execution = WorkflowExecution( | ||||
| id="test-workflow-run-id", | |||||
| id_="test-workflow-run-id", | |||||
| workflow_id="test-workflow-id", | workflow_id="test-workflow-id", | ||||
| workflow_version="1.0", | workflow_version="1.0", | ||||
| sequence_number=1, | |||||
| type=WorkflowType.CHAT, | |||||
| workflow_type=WorkflowType.CHAT, | |||||
| graph={"nodes": [], "edges": []}, | graph={"nodes": [], "edges": []}, | ||||
| inputs={"query": "test query"}, | inputs={"query": "test query"}, | ||||
| started_at=datetime.now(UTC).replace(tzinfo=None), | started_at=datetime.now(UTC).replace(tzinfo=None), | ||||
| workflow_run_id="test-workflow-run-id", | workflow_run_id="test-workflow-run-id", | ||||
| total_tokens=50, | total_tokens=50, | ||||
| total_steps=3, | total_steps=3, | ||||
| status=WorkflowRunStatus.FAILED, | |||||
| status=WorkflowExecutionStatus.FAILED, | |||||
| error_message="Test error message", | error_message="Test error message", | ||||
| ) | ) | ||||
| # Verify the result | # Verify the result | ||||
| assert result == workflow_execution | assert result == workflow_execution | ||||
| assert result.status == WorkflowExecutionStatus(WorkflowRunStatus.FAILED.value) | |||||
| assert result.status == WorkflowExecutionStatus.FAILED | |||||
| assert result.error_message == "Test error message" | assert result.error_message == "Test error message" | ||||
| assert result.total_tokens == 50 | assert result.total_tokens == 50 | ||||
| assert result.total_steps == 3 | assert result.total_steps == 3 | ||||
| # Create a real WorkflowExecution | # Create a real WorkflowExecution | ||||
| workflow_execution = WorkflowExecution( | workflow_execution = WorkflowExecution( | ||||
| id="test-workflow-execution-id", | |||||
| id_="test-workflow-execution-id", | |||||
| workflow_id="test-workflow-id", | workflow_id="test-workflow-id", | ||||
| workflow_version="1.0", | workflow_version="1.0", | ||||
| sequence_number=1, | |||||
| type=WorkflowType.CHAT, | |||||
| workflow_type=WorkflowType.CHAT, | |||||
| graph={"nodes": [], "edges": []}, | graph={"nodes": [], "edges": []}, | ||||
| inputs={"query": "test query"}, | inputs={"query": "test query"}, | ||||
| started_at=datetime.now(UTC).replace(tzinfo=None), | started_at=datetime.now(UTC).replace(tzinfo=None), | ||||
| # Call the method | # Call the method | ||||
| result = workflow_cycle_manager.handle_node_execution_start( | result = workflow_cycle_manager.handle_node_execution_start( | ||||
| workflow_execution_id=workflow_execution.id, | |||||
| workflow_execution_id=workflow_execution.id_, | |||||
| event=event, | event=event, | ||||
| ) | ) | ||||
| # Verify the result | # Verify the result | ||||
| assert result.workflow_id == workflow_execution.workflow_id | assert result.workflow_id == workflow_execution.workflow_id | ||||
| assert result.workflow_run_id == workflow_execution.id | |||||
| assert result.workflow_run_id == workflow_execution.id_ | |||||
| assert result.node_execution_id == event.node_execution_id | assert result.node_execution_id == event.node_execution_id | ||||
| assert result.node_id == event.node_id | assert result.node_id == event.node_id | ||||
| assert result.node_type == event.node_type | assert result.node_type == event.node_type | ||||
| assert result.title == event.node_data.title | assert result.title == event.node_data.title | ||||
| assert result.status == NodeExecutionStatus.RUNNING | |||||
| assert result.status == WorkflowNodeExecutionStatus.RUNNING | |||||
| # Verify save was called | # Verify save was called | ||||
| workflow_cycle_manager._workflow_node_execution_repository.save.assert_called_once_with(result) | workflow_cycle_manager._workflow_node_execution_repository.save.assert_called_once_with(result) | ||||
| # Create a real WorkflowExecution | # Create a real WorkflowExecution | ||||
| workflow_execution = WorkflowExecution( | workflow_execution = WorkflowExecution( | ||||
| id="test-workflow-run-id", | |||||
| id_="test-workflow-run-id", | |||||
| workflow_id="test-workflow-id", | workflow_id="test-workflow-id", | ||||
| workflow_version="1.0", | workflow_version="1.0", | ||||
| sequence_number=1, | |||||
| type=WorkflowType.CHAT, | |||||
| workflow_type=WorkflowType.CHAT, | |||||
| graph={"nodes": [], "edges": []}, | graph={"nodes": [], "edges": []}, | ||||
| inputs={"query": "test query"}, | inputs={"query": "test query"}, | ||||
| started_at=datetime.now(UTC).replace(tzinfo=None), | started_at=datetime.now(UTC).replace(tzinfo=None), | ||||
| # Verify the result | # Verify the result | ||||
| assert result == node_execution | assert result == node_execution | ||||
| assert result.status == NodeExecutionStatus.SUCCEEDED | |||||
| assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED | |||||
| # Verify save was called | # Verify save was called | ||||
| workflow_cycle_manager._workflow_node_execution_repository.save.assert_called_once_with(node_execution) | workflow_cycle_manager._workflow_node_execution_repository.save.assert_called_once_with(node_execution) | ||||
| # Create a real WorkflowExecution | # Create a real WorkflowExecution | ||||
| workflow_execution = WorkflowExecution( | workflow_execution = WorkflowExecution( | ||||
| id="test-workflow-run-id", | |||||
| id_="test-workflow-run-id", | |||||
| workflow_id="test-workflow-id", | workflow_id="test-workflow-id", | ||||
| workflow_version="1.0", | workflow_version="1.0", | ||||
| sequence_number=1, | |||||
| type=WorkflowType.CHAT, | |||||
| workflow_type=WorkflowType.CHAT, | |||||
| graph={"nodes": [], "edges": []}, | graph={"nodes": [], "edges": []}, | ||||
| inputs={"query": "test query"}, | inputs={"query": "test query"}, | ||||
| started_at=datetime.now(UTC).replace(tzinfo=None), | started_at=datetime.now(UTC).replace(tzinfo=None), | ||||
| # Verify the result | # Verify the result | ||||
| assert result == node_execution | assert result == node_execution | ||||
| assert result.status == NodeExecutionStatus.FAILED | |||||
| assert result.status == WorkflowNodeExecutionStatus.FAILED | |||||
| assert result.error == "Test error message" | assert result.error == "Test error message" | ||||
| # Verify save was called | # Verify save was called |
| from core.model_runtime.utils.encoders import jsonable_encoder | from core.model_runtime.utils.encoders import jsonable_encoder | ||||
| from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository | ||||
| from core.workflow.entities.node_entities import NodeRunMetadataKey | |||||
| from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus | |||||
| from core.workflow.entities.workflow_node_execution import ( | |||||
| NodeExecution, | |||||
| NodeRunMetadataKey, | |||||
| WorkflowNodeExecutionStatus, | |||||
| ) | |||||
| from core.workflow.nodes.enums import NodeType | from core.workflow.nodes.enums import NodeType | ||||
| from core.workflow.repository.workflow_node_execution_repository import OrderConfig | |||||
| from core.workflow.repositories.workflow_node_execution_repository import OrderConfig | |||||
| from models.account import Account, Tenant | from models.account import Account, Tenant | ||||
| from models.workflow import WorkflowNodeExecution, WorkflowNodeExecutionStatus, WorkflowNodeExecutionTriggeredFrom | |||||
| from models.workflow import WorkflowNodeExecution, WorkflowNodeExecutionTriggeredFrom | |||||
| def configure_mock_execution(mock_execution): | def configure_mock_execution(mock_execution): | ||||
| inputs={"input_key": "input_value"}, | inputs={"input_key": "input_value"}, | ||||
| process_data={"process_key": "process_value"}, | process_data={"process_key": "process_value"}, | ||||
| outputs={"output_key": "output_value"}, | outputs={"output_key": "output_value"}, | ||||
| status=NodeExecutionStatus.RUNNING, | |||||
| status=WorkflowNodeExecutionStatus.RUNNING, | |||||
| error=None, | error=None, | ||||
| elapsed_time=1.5, | elapsed_time=1.5, | ||||
| metadata={NodeRunMetadataKey.TOTAL_TOKENS: 100, NodeRunMetadataKey.TOTAL_PRICE: Decimal("0.0")}, | metadata={NodeRunMetadataKey.TOTAL_TOKENS: 100, NodeRunMetadataKey.TOTAL_PRICE: Decimal("0.0")}, | ||||
| assert domain_model.inputs == inputs_dict | assert domain_model.inputs == inputs_dict | ||||
| assert domain_model.process_data == process_data_dict | assert domain_model.process_data == process_data_dict | ||||
| assert domain_model.outputs == outputs_dict | assert domain_model.outputs == outputs_dict | ||||
| assert domain_model.status == NodeExecutionStatus(db_model.status) | |||||
| assert domain_model.status == WorkflowNodeExecutionStatus(db_model.status) | |||||
| assert domain_model.error == db_model.error | assert domain_model.error == db_model.error | ||||
| assert domain_model.elapsed_time == db_model.elapsed_time | assert domain_model.elapsed_time == db_model.elapsed_time | ||||
| assert domain_model.metadata == metadata_dict | assert domain_model.metadata == metadata_dict |