Limit pending restoration to sessions reloaded from storage
This commit is contained in:
1 parent
4f5a928a6e
commit
4e8029f20e
2 files changed
+48
-5
No files matched your search
@@ -246,6 +246,7 @@ class Session:
|
||||
partial: Optional[dict] = None
|
||||
status: str = "idle" # idle|running|error|cancelled
|
||||
agent: Any = None
|
||||
pending_restore: bool = False # Only records read back from storage await restoration.
|
||||
thread: Optional[threading.Thread] = None
|
||||
cancel_requested: bool = False
|
||||
active_turn_id: str = ""
|
||||
@@ -463,7 +464,8 @@ class AgentManager:
|
||||
plan_path=_sanitize_desktop_plan_path(item["id"], item["plan_path"]),
|
||||
llm_no=item["llm_no"],
|
||||
first_message=meta["first_message"], first_message_at=meta["first_message_at"],
|
||||
log_refs=meta["log_refs"], has_content=meta["has_content"])
|
||||
log_refs=meta["log_refs"], has_content=meta["has_content"],
|
||||
pending_restore=True)
|
||||
|
||||
def _load_sessions(self):
|
||||
# New format: one file per session under temp/desktop_sessions/.
|
||||
@@ -762,6 +764,7 @@ class AgentManager:
|
||||
agent.verbose = True
|
||||
threading.Thread(target=agent.run, daemon=True, name=f"GA-{sess.id}").start()
|
||||
sess.agent = agent
|
||||
sess.pending_restore = False
|
||||
self._sync_display_cache(sess)
|
||||
from frontends import hub
|
||||
hub.connect(agent, f"desktop-{sess.id}",
|
||||
@@ -965,7 +968,7 @@ class AgentManager:
|
||||
"title": sess.title,
|
||||
"cwd": sess.cwd,
|
||||
"status": sess.status,
|
||||
"loaded": sess.agent is not None,
|
||||
"loaded": not sess.pending_restore,
|
||||
"createdAt": sess.created_at,
|
||||
"updatedAt": sess.updated_at,
|
||||
"lastError": sess.last_error,
|
||||
@@ -1054,7 +1057,10 @@ class AgentManager:
|
||||
if sess.status == "running":
|
||||
raise web.HTTPConflict(text=json.dumps({"error": "session is already running"}, ensure_ascii=False), content_type="application/json")
|
||||
if sess.agent is None and _e2e_control_token() is None:
|
||||
self.restore_context(sid)
|
||||
if sess.pending_restore:
|
||||
self.restore_context(sid)
|
||||
else:
|
||||
self.make_agent(sess)
|
||||
extra = {}
|
||||
if image_ids:
|
||||
extra["image_ids"] = image_ids
|
||||
@@ -1155,7 +1161,8 @@ class AgentManager:
|
||||
emit_session_state(sess, "idle")
|
||||
return
|
||||
if sess.agent is None:
|
||||
self.restore_context(sess.id)
|
||||
with self.mutation():
|
||||
self.make_agent(sess)
|
||||
agent = sess.agent
|
||||
from desktop_history import preview
|
||||
log_path = getattr(agent, "log_path", None)
|
||||
@@ -1354,7 +1361,7 @@ class AgentManager:
|
||||
sess = self.sessions.get(sid)
|
||||
if not sess:
|
||||
raise web.HTTPNotFound(text=json.dumps({"error": f"session not found: {sid}"}), content_type="application/json")
|
||||
if sess.agent is not None:
|
||||
if not sess.pending_restore:
|
||||
return {"ok": True, "sessionId": sid, "restored": False, "loaded": True}
|
||||
try:
|
||||
self.make_agent(sess)
|
||||
|
||||
@@ -198,3 +198,39 @@ def test_display_cache_is_rebuildable_and_follows_ga(manager):
|
||||
sess.agent.all_outputs.clear()
|
||||
manager._sync_display_cache(sess)
|
||||
assert sess.messages == []
|
||||
|
||||
|
||||
def test_new_session_is_not_pending_restore_until_bridge_reload(manager, monkeypatch):
|
||||
sess = manager.create_session()
|
||||
assert sess.agent is None
|
||||
assert manager.snapshot(sess)['loaded'] is True
|
||||
def unexpected(*args, **kwargs):
|
||||
raise AssertionError('normal session must not enter history restoration')
|
||||
monkeypatch.setattr(manager, 'make_agent', unexpected)
|
||||
assert manager.restore_context(sess.id)['restored'] is False
|
||||
manager.set_session_model(sess.id, 1)
|
||||
assert manager.snapshot(sess)['loaded'] is True
|
||||
assert 'pending_restore' not in manager._session_dict(sess)
|
||||
manager.sessions.clear()
|
||||
manager._load_sessions()
|
||||
restored = manager.sessions[sess.id]
|
||||
assert restored.agent is None
|
||||
assert manager.snapshot(restored)['loaded'] is False
|
||||
|
||||
|
||||
def test_new_prompt_initializes_ga_without_restore_path(manager, monkeypatch):
|
||||
monkeypatch.setattr(sys.modules['plan_state'], 'sync_plan_path_from_text', lambda *a: None, raising=False)
|
||||
sess = manager.create_session()
|
||||
monkeypatch.setattr(manager, 'ensure_ga_import_path', lambda: Path(manager.ga_root))
|
||||
monkeypatch.setitem(sys.modules, 'agentmain', _make_stub('agentmain', {'GenericAgent': FakeAgent}))
|
||||
monkeypatch.setattr(hub, 'connect', lambda *a, **kw: None)
|
||||
def unexpected(*args, **kwargs):
|
||||
raise AssertionError('new prompt must not enter history restoration')
|
||||
monkeypatch.setattr(manager, 'restore_context', unexpected)
|
||||
result = manager.submit_prompt(sess.id, 'hello')
|
||||
assert result['accepted']
|
||||
sess.thread.join(timeout=3)
|
||||
assert not sess.thread.is_alive()
|
||||
assert sess.agent is not None
|
||||
assert manager.snapshot(sess)['loaded'] is True
|
||||
assert sess.status == 'idle'
|
||||
Reference in new issue
Block a user