diff --git a/gateway/run.py b/gateway/run.py index afc5aa035..7b9622485 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -2546,11 +2546,8 @@ class GatewayRunner: self._pending_messages.pop(_quick_key, None) if _quick_key in self._running_agents: del self._running_agents[_quick_key] - # Mark session suspended so the next message starts fresh - # instead of resuming the stuck context (#7536). - self.session_store.suspend_session(_quick_key) - logger.info("HARD STOP for session %s — suspended, session lock released", _quick_key[:20]) - return "⚡ Force-stopped. The session is suspended — your next message will start fresh." + logger.info("STOP for session %s — agent interrupted, session lock released", _quick_key[:20]) + return "⚡ Stopped. You can continue this session." # /reset and /new must bypass the running-agent guard so they # actually dispatch as commands instead of being queued as user @@ -4120,9 +4117,7 @@ class GatewayRunner: only through normal command dispatch (no running agent) or as a fallback. Force-clean the session lock in all cases for safety. - When there IS a running/pending agent, the session is also marked - as *suspended* so the next message starts a fresh session instead - of resuming the stuck context (#7536). + The session is preserved so the user can continue the conversation. """ source = event.source session_entry = self.session_store.get_or_create_session(source) @@ -4133,17 +4128,15 @@ class GatewayRunner: # Force-clean the sentinel so the session is unlocked. if session_key in self._running_agents: del self._running_agents[session_key] - self.session_store.suspend_session(session_key) - logger.info("HARD STOP (pending) for session %s — suspended, sentinel cleared", session_key[:20]) - return "⚡ Force-stopped. The agent was still starting — your next message will start fresh." + logger.info("STOP (pending) for session %s — sentinel cleared", session_key[:20]) + return "⚡ Stopped. The agent hadn't started yet — you can continue this session." if agent: agent.interrupt("Stop requested") # Force-clean the session lock so a truly hung agent doesn't # keep it locked forever. if session_key in self._running_agents: del self._running_agents[session_key] - self.session_store.suspend_session(session_key) - return "⚡ Force-stopped. Your next message will start a fresh session." + return "⚡ Stopped. You can continue this session." else: return "No active task to stop." diff --git a/tests/gateway/test_session_race_guard.py b/tests/gateway/test_session_race_guard.py index c9e226b67..fcfaba784 100644 --- a/tests/gateway/test_session_race_guard.py +++ b/tests/gateway/test_session_race_guard.py @@ -242,9 +242,7 @@ async def test_stop_during_sentinel_force_cleans_session(): stop_event = _make_event(text="/stop") result = await runner._handle_message(stop_event) assert result is not None, "/stop during sentinel should return a message" - assert "force-stopped" in result.lower() or "unlocked" in result.lower() - - # Sentinel must be cleaned up + assert "stopped" in result.lower() assert session_key not in runner._running_agents, ( "/stop must remove sentinel so the session is unlocked" ) @@ -291,7 +289,7 @@ async def test_stop_hard_kills_running_agent(): # Must return a confirmation assert result is not None - assert "force-stopped" in result.lower() or "unlocked" in result.lower() + assert "stopped" in result.lower() # ------------------------------------------------------------------