Fix Studio manual node switch state transitions so revisitable steps stay accessible after switching away.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -400,6 +400,60 @@ class StudioRunService:
|
||||
draft = state.lastDraft or {}
|
||||
return bool(draft.get("writtenEntryUid")) or state.status == "completed"
|
||||
|
||||
@staticmethod
|
||||
def _init_bind_completed(state: StudioNodeRunState) -> bool:
|
||||
draft = state.lastDraft or {}
|
||||
return bool(draft.get("characterId") and draft.get("worldbookId")) or (
|
||||
state.status == "completed"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _node_has_draft_progress(state: StudioNodeRunState) -> bool:
|
||||
"""Node has user-visible progress even if not yet exported to worldbook."""
|
||||
draft = state.lastDraft or {}
|
||||
if state.skillId == "studio.worldbook_entry":
|
||||
return bool(
|
||||
(draft.get("entryContent") or "").strip()
|
||||
or draft.get("writtenEntryUid")
|
||||
or state.stepMessages
|
||||
)
|
||||
if state.skillId == "studio.init_bind":
|
||||
return bool(
|
||||
(draft.get("characterId") and draft.get("worldbookId"))
|
||||
or draft.get("displayParams")
|
||||
)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _node_is_revisitable(state: StudioNodeRunState) -> bool:
|
||||
if state.status in ("active", "completed"):
|
||||
return True
|
||||
if state.status == "pending":
|
||||
return StudioRunService._node_has_draft_progress(state)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _status_after_leaving_active_node(state: StudioNodeRunState) -> str:
|
||||
if state.status == "completed":
|
||||
return "completed"
|
||||
if state.status != "active":
|
||||
return state.status
|
||||
if state.skillId == "studio.worldbook_entry":
|
||||
if (
|
||||
StudioRunService._node_has_written_entry(state)
|
||||
or StudioRunService._node_has_draft_progress(state)
|
||||
):
|
||||
return "completed"
|
||||
return "pending"
|
||||
if state.skillId == "studio.init_bind":
|
||||
if (
|
||||
StudioRunService._init_bind_completed(state)
|
||||
or StudioRunService._node_has_draft_progress(state)
|
||||
):
|
||||
return "completed"
|
||||
return "pending"
|
||||
return state.status
|
||||
|
||||
def _save_worldbook_entry_only(
|
||||
self,
|
||||
project_id: str,
|
||||
@@ -603,16 +657,16 @@ class StudioRunService:
|
||||
raise ValueError(f"节点不存在:{node_id}")
|
||||
if not target_node.enabled:
|
||||
raise ValueError("该节点已禁用,无法切换")
|
||||
if target_node.skillId != "studio.worldbook_entry":
|
||||
raise ValueError("仅支持切换到世界书创作步骤")
|
||||
if target_node.skillId not in ("studio.worldbook_entry", "studio.init_bind"):
|
||||
raise ValueError("仅支持切换到初始化绑定或世界书创作步骤")
|
||||
|
||||
target_state = next(
|
||||
(s for s in run.nodeStates if s.nodeId == node_id), None
|
||||
)
|
||||
if not target_state:
|
||||
raise ValueError("节点状态不存在")
|
||||
if target_state.status not in ("active", "completed"):
|
||||
raise ValueError("仅可切换到进行中或已完成的步骤")
|
||||
if not self._node_is_revisitable(target_state):
|
||||
raise ValueError("仅可切换到已有进度的步骤")
|
||||
|
||||
prev_node_id = run.currentNodeId
|
||||
now = datetime.now().isoformat()
|
||||
@@ -623,11 +677,7 @@ class StudioRunService:
|
||||
if state.nodeId == node_id:
|
||||
updated.status = "active"
|
||||
elif prev_node_id and state.nodeId == prev_node_id and prev_node_id != node_id:
|
||||
if state.skillId == "studio.worldbook_entry":
|
||||
if self._node_has_written_entry(state):
|
||||
updated.status = "completed"
|
||||
else:
|
||||
updated.status = "pending"
|
||||
updated.status = self._status_after_leaving_active_node(state)
|
||||
new_node_states.append(updated)
|
||||
|
||||
new_status = (
|
||||
|
||||
Reference in New Issue
Block a user