from collections.abc import Sequence from datetime import datetime from pydantic import Field from core.rag.entities.citation_metadata import RetrievalSourceMetadata from dify_graph.entities import AgentNodeStrategyInit from dify_graph.entities.pause_reason import PauseReason from .base import GraphNodeEventBase class NodeRunStartedEvent(GraphNodeEventBase): node_title: str predecessor_node_id: str | None = None agent_strategy: AgentNodeStrategyInit | None = None start_at: datetime = Field(..., description="node start time") # FIXME(-LAN-): only for ToolNode provider_type: str = "" provider_id: str = "" class NodeRunStreamChunkEvent(GraphNodeEventBase): # Spec-compliant fields selector: Sequence[str] = Field( ..., description="selector identifying the output location (e.g., ['nodeA', 'text'])" ) chunk: str = Field(..., description="the actual chunk content") is_final: bool = Field(default=False, description="indicates if this is the last chunk") class NodeRunRetrieverResourceEvent(GraphNodeEventBase): retriever_resources: Sequence[RetrievalSourceMetadata] = Field(..., description="retriever resources") context: str = Field(..., description="context") class NodeRunSucceededEvent(GraphNodeEventBase): start_at: datetime = Field(..., description="node start time") class NodeRunFailedEvent(GraphNodeEventBase): error: str = Field(..., description="error") start_at: datetime = Field(..., description="node start time") class NodeRunExceptionEvent(GraphNodeEventBase): error: str = Field(..., description="error") start_at: datetime = Field(..., description="node start time") class NodeRunRetryEvent(NodeRunStartedEvent): error: str = Field(..., description="error") retry_index: int = Field(..., description="which retry attempt is about to be performed") class NodeRunHumanInputFormFilledEvent(GraphNodeEventBase): """Emitted when a HumanInput form is submitted and before the node finishes.""" node_title: str = Field(..., description="HumanInput node title") rendered_content: str = Field(..., description="Markdown content rendered with user inputs.") action_id: str = Field(..., description="User action identifier chosen in the form.") action_text: str = Field(..., description="Display text of the chosen action button.") class NodeRunHumanInputFormTimeoutEvent(GraphNodeEventBase): """Emitted when a HumanInput form times out.""" node_title: str = Field(..., description="HumanInput node title") expiration_time: datetime = Field(..., description="Form expiration time") class NodeRunPauseRequestedEvent(GraphNodeEventBase): reason: PauseReason = Field(..., description="pause reason") def is_node_result_event(event: GraphNodeEventBase) -> bool: """ Check if an event is a final result event from node execution. A result event indicates the completion of a node execution and contains runtime information such as inputs, outputs, or error details. Args: event: The event to check Returns: True if the event is a node result event (succeeded/failed/paused), False otherwise """ return isinstance( event, ( NodeRunSucceededEvent, NodeRunFailedEvent, NodeRunPauseRequestedEvent, ), )