mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-09 19:27:45 +02:00
[eric] agents: a chat still running when the backend shuts down says so in its transcript, instead of reading like the user's own Stop
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012G8kyALnPjsA7aJFmMBq3R
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
fc0604155e
commit
6d97692ea7
@@ -10,7 +10,7 @@ from typing import Optional
|
||||
|
||||
from typeguard import typechecked
|
||||
|
||||
from backend.apps.agents.core.models import AgentSession
|
||||
from backend.apps.agents.core.models import AgentSession, Message
|
||||
from backend.apps.agents.core.ws_manager import ws_manager
|
||||
from backend.apps.agents.manager.session.session_store import (
|
||||
load_all_session_data,
|
||||
@@ -49,6 +49,12 @@ def running_under_test() -> bool:
|
||||
from backend.apps.agents.manager.AgentManagerProtocol import AgentManagerProtocol
|
||||
|
||||
|
||||
SHUTDOWN_STOP_NOTE = (
|
||||
"This chat was still running when OpenSwarm's engine shut down, so it stopped here; that was not "
|
||||
"your Stop. Send a message to continue from where it left off."
|
||||
)
|
||||
|
||||
|
||||
class SessionPersistence(AgentManagerProtocol):
|
||||
@typechecked
|
||||
async def reconcile_on_startup(self) -> None:
|
||||
@@ -134,6 +140,10 @@ class SessionPersistence(AgentManagerProtocol):
|
||||
for session_id, session in list(self.sessions.items()):
|
||||
if session.status in ("running", "waiting_approval"):
|
||||
session.status = "stopped"
|
||||
# Say who stopped it. A chat flushed as plain "stopped" reads exactly like the user's own
|
||||
# Stop, and when something else killed the backend (an agent's pkill, 2026-09-01) the
|
||||
# user's running work vanished with nothing saying why: silent loss, row 1.
|
||||
session.messages.append(Message(role="system", content=SHUTDOWN_STOP_NOTE, branch_id=session.active_branch_id))
|
||||
session.closed_at = None
|
||||
for req in list(session.pending_approvals):
|
||||
ws_manager.resolve_approval(req.id, {"behavior": "deny", "message": "Server shutting down"})
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
"""A chat that was running when the backend shut down must say so, or the flush reads as the user's Stop.
|
||||
|
||||
2026-09-01: an agent's `pkill -f uvicorn` SIGTERMed Eric's production backend twice; every running chat
|
||||
was persisted as plain "stopped" and nothing in the transcript said why (row 1, silent work loss)."""
|
||||
import asyncio
|
||||
from backend.apps.agents.agent_manager import agent_manager
|
||||
from backend.apps.agents.core.models import AgentSession, Message
|
||||
from backend.apps.agents.manager.session import SessionPersistence as sp
|
||||
|
||||
|
||||
def p_session(status: str) -> AgentSession:
|
||||
s = AgentSession(name="t", model="sonnet", status=status)
|
||||
s.messages.append(Message(role="user", content="build the thing", branch_id="main"))
|
||||
return s
|
||||
|
||||
|
||||
def test_a_running_chat_gets_the_shutdown_note_and_stops(monkeypatch, tmp_path) -> None:
|
||||
saved: dict = {}
|
||||
monkeypatch.setattr(sp, "save_session", lambda sid, doc: saved.__setitem__(sid, doc))
|
||||
s = p_session("running")
|
||||
agent_manager.sessions.clear(); agent_manager.sessions[s.id] = s
|
||||
asyncio.run(agent_manager.persist_all_sessions())
|
||||
doc = saved[s.id]
|
||||
assert doc["status"] == "stopped"
|
||||
last = doc["messages"][-1]
|
||||
assert last["role"] == "system", "the note is the platform speaking, never the model"
|
||||
assert "not your Stop" in last["content"] and "Send a message to continue" in last["content"]
|
||||
|
||||
|
||||
def test_a_settled_chat_is_flushed_untouched(monkeypatch) -> None:
|
||||
saved: dict = {}
|
||||
monkeypatch.setattr(sp, "save_session", lambda sid, doc: saved.__setitem__(sid, doc))
|
||||
s = p_session("completed")
|
||||
agent_manager.sessions.clear(); agent_manager.sessions[s.id] = s
|
||||
asyncio.run(agent_manager.persist_all_sessions())
|
||||
doc = saved[s.id]
|
||||
assert doc["status"] == "completed"
|
||||
assert doc["messages"][-1]["role"] == "user", "no note on a chat that was not running"
|
||||
Reference in New Issue
Block a user