fix(api): Ensure is_resumption for node_started event is correctly set

This commit is contained in:
QuantumGhost
2026-01-13 09:25:44 +08:00
parent 5523df6023
commit 6bcd4ad740
9 changed files with 76 additions and 20 deletions

View File

@ -236,3 +236,10 @@ class GraphExecution:
def record_node_failure(self) -> None:
"""Increment the count of node failures encountered during execution."""
self.exceptions_count += 1
def is_node_resumption(self, node_id: str, execution_id: str) -> bool:
"""Return True if the node is resuming a previously started execution."""
node_execution = self.node_executions.get(node_id)
if not node_execution or not node_execution.execution_id:
return False
return str(node_execution.execution_id) == execution_id

View File

@ -131,9 +131,6 @@ class EventHandler:
node_execution.mark_started(event.id)
self._graph_runtime_state.increment_node_run_steps()
# Mark whether this start is part of a resume flow
event.is_resumption = self._graph_runtime_state.consume_resuming_node(event.node_id)
# Track in response coordinator for stream ordering
self._response_coordinator.track_node_execution(event.node_id, event.id)

View File

@ -15,7 +15,10 @@ class NodeRunStartedEvent(GraphNodeEventBase):
predecessor_node_id: str | None = None
agent_strategy: AgentNodeStrategyInit | None = None
start_at: datetime = Field(..., description="node start time")
is_resumption: bool = False
is_resumption: bool = Field(
default=False,
description="True only when this node had already started and execution resumed after a pause.",
)
# FIXME(-LAN-): only for ToolNode
provider_type: str = ""

View File

@ -301,6 +301,7 @@ class Node(Generic[NodeDataT]):
def run(self) -> Generator[GraphNodeEventBase, None, None]:
execution_id = self.ensure_execution_id()
self._start_at = naive_utc_now()
is_resumption = self.graph_runtime_state.is_node_resumption(self._node_id, execution_id)
# Create and push start event with required fields
start_event = NodeRunStartedEvent(
@ -310,6 +311,7 @@ class Node(Generic[NodeDataT]):
node_title=self.title,
in_iteration_id=None,
start_at=self._start_at,
is_resumption=is_resumption,
)
# === FIXME(-LAN-): Needs to refactor.

View File

@ -79,6 +79,10 @@ class GraphExecutionProtocol(Protocol):
"""Record an unrecoverable error and end execution."""
...
def is_node_resumption(self, node_id: str, execution_id: str) -> bool:
"""Return True if the node is resuming a previously started execution."""
...
def dumps(self) -> str:
"""Serialize execution state into a JSON payload."""
...
@ -179,8 +183,11 @@ class GraphRuntimeState:
self._pending_graph_execution_workflow_id: str | None = None
self._paused_nodes: set[str] = set()
self._deferred_nodes: set[str] = set()
# Tracks nodes that are being resumed in the current execution cycle.
# Populated when paused nodes are consumed during resume.
# Semantic meaning:
# A node id in this set represents "the same node execution is continuing after a pause".
# It means the node has already started in a previous cycle, was paused, and is now resuming,
# so its next node_started event should be marked as a resumption.
# It does NOT mean "any node that runs after resume", and excludes never-run nodes.
self._resuming_nodes: set[str] = set()
if graph is not None:
@ -399,6 +406,14 @@ class GraphRuntimeState:
return True
return False
def is_node_resumption(self, node_id: str, execution_id: str) -> bool:
"""
Return True if the node is resuming a previously started execution.
"""
if self.consume_resuming_node(node_id):
return True
return self.graph_execution.is_node_resumption(node_id, execution_id)
# ------------------------------------------------------------------
# Builders
# ------------------------------------------------------------------