mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-18 14:52:04 +00:00
Keep resumed profile cwd scoped to profile DB
This commit is contained in:
parent
4936a49a0c
commit
d842155da1
2 changed files with 124 additions and 7 deletions
|
|
@ -940,7 +940,7 @@ def test_session_resume_uses_parent_lineage_for_display(monkeypatch):
|
|||
lambda agent, *a: {"model": "test", "tools": {}, "skills": {}},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
server, "_init_session", lambda sid, key, agent, history, cols=80: None
|
||||
server, "_init_session", lambda sid, key, agent, history, cols=80, **_kwargs: None
|
||||
)
|
||||
|
||||
resp = server.handle_request(
|
||||
|
|
@ -983,7 +983,7 @@ def test_session_resume_passes_stored_runtime_to_agent(monkeypatch):
|
|||
monkeypatch.setattr(server, "_make_agent", fake_make_agent)
|
||||
monkeypatch.setattr(server, "_session_info", lambda agent, *a: {"model": agent.model, "provider": agent.provider})
|
||||
|
||||
def fake_init_session(sid, key, agent, history, cols=80):
|
||||
def fake_init_session(sid, key, agent, history, cols=80, **_kwargs):
|
||||
server._sessions[sid] = {"agent": agent, "session_key": key}
|
||||
|
||||
monkeypatch.setattr(server, "_init_session", fake_init_session)
|
||||
|
|
@ -1006,6 +1006,94 @@ def test_session_resume_passes_stored_runtime_to_agent(monkeypatch):
|
|||
assert server._sessions[runtime_sid]["model_override"] == captured["model_override"]
|
||||
|
||||
|
||||
def test_session_resume_profile_uses_profile_db_cwd(monkeypatch, tmp_path):
|
||||
target = "stored-profile-session"
|
||||
launch_cwd = tmp_path / "launch"
|
||||
profile_cwd = tmp_path / "worker"
|
||||
profile_home = tmp_path / "profiles" / "worker"
|
||||
launch_cwd.mkdir()
|
||||
profile_cwd.mkdir()
|
||||
profile_home.mkdir(parents=True)
|
||||
captured = {}
|
||||
|
||||
class ProfileDB:
|
||||
def get_session(self, _target):
|
||||
return {"id": target, "cwd": str(profile_cwd)}
|
||||
|
||||
def get_session_by_title(self, _target):
|
||||
return None
|
||||
|
||||
def reopen_session(self, _target):
|
||||
captured["reopened"] = _target
|
||||
|
||||
def get_messages_as_conversation(self, _target, include_ancestors=False):
|
||||
return [{"role": "user", "content": "hello"}]
|
||||
|
||||
def update_session_cwd(self, *_args):
|
||||
raise AssertionError("profile row already has cwd")
|
||||
|
||||
class LaunchDB:
|
||||
def get_session(self, _target):
|
||||
return {"id": target, "cwd": str(launch_cwd)}
|
||||
|
||||
def update_session_cwd(self, *_args):
|
||||
captured["launch_update"] = True
|
||||
|
||||
profile_db = ProfileDB()
|
||||
launch_db = LaunchDB()
|
||||
|
||||
class FakeWorker:
|
||||
def __init__(self, *_args, **_kwargs):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def fake_make_agent(sid, key, session_id=None, session_db=None, **kwargs):
|
||||
captured["agent_db"] = session_db
|
||||
return types.SimpleNamespace(model="test/model")
|
||||
|
||||
monkeypatch.setenv("TERMINAL_CWD", str(launch_cwd))
|
||||
monkeypatch.setattr(server, "_profile_home", lambda _profile: profile_home)
|
||||
monkeypatch.setattr("hermes_state.SessionDB", lambda db_path=None: profile_db)
|
||||
monkeypatch.setattr(server, "_get_db", lambda: launch_db)
|
||||
monkeypatch.setattr(server, "_enable_gateway_prompts", lambda: None)
|
||||
monkeypatch.setattr(server, "_set_session_context", lambda target: [])
|
||||
monkeypatch.setattr(server, "_clear_session_context", lambda tokens: None)
|
||||
monkeypatch.setattr(server, "_make_agent", fake_make_agent)
|
||||
monkeypatch.setattr(server, "_SlashWorker", FakeWorker)
|
||||
monkeypatch.setattr(server, "_wire_callbacks", lambda _sid: None)
|
||||
monkeypatch.setattr(server, "_emit", lambda *args, **kwargs: None)
|
||||
monkeypatch.setattr(
|
||||
server,
|
||||
"_session_info",
|
||||
lambda _agent, session=None: {"cwd": session.get("cwd") if session else ""},
|
||||
)
|
||||
|
||||
import tools.approval as approval
|
||||
|
||||
monkeypatch.setattr(approval, "register_gateway_notify", lambda key, cb: None)
|
||||
monkeypatch.setattr(approval, "load_permanent_allowlist", lambda: None)
|
||||
|
||||
try:
|
||||
resp = server.handle_request(
|
||||
{
|
||||
"id": "1",
|
||||
"method": "session.resume",
|
||||
"params": {"session_id": target, "profile": "worker"},
|
||||
}
|
||||
)
|
||||
|
||||
assert "error" not in resp
|
||||
sid = resp["result"]["session_id"]
|
||||
assert captured["agent_db"] is profile_db
|
||||
assert server._sessions[sid]["cwd"] == str(profile_cwd)
|
||||
assert resp["result"]["info"]["cwd"] == str(profile_cwd)
|
||||
assert "launch_update" not in captured
|
||||
finally:
|
||||
server._sessions.clear()
|
||||
|
||||
|
||||
def test_stored_session_runtime_overrides_skips_bare_billing_provider():
|
||||
"""A bare billing bucket ("custom"/"auto"/"openrouter") must not be restored as the
|
||||
provider identity on resume. A custom endpoint that never used `/model` persists only
|
||||
|
|
|
|||
|
|
@ -3428,7 +3428,15 @@ def _make_agent(
|
|||
)
|
||||
|
||||
|
||||
def _init_session(sid: str, key: str, agent, history: list, cols: int = 80):
|
||||
def _init_session(
|
||||
sid: str,
|
||||
key: str,
|
||||
agent,
|
||||
history: list,
|
||||
cols: int = 80,
|
||||
cwd: str | None = None,
|
||||
session_db=None,
|
||||
):
|
||||
now = time.time()
|
||||
with _sessions_lock:
|
||||
_sessions[sid] = {
|
||||
|
|
@ -3443,7 +3451,7 @@ def _init_session(sid: str, key: str, agent, history: list, cols: int = 80):
|
|||
"running": False,
|
||||
"attached_images": [],
|
||||
"image_counter": 0,
|
||||
"cwd": _completion_cwd(),
|
||||
"cwd": cwd or _completion_cwd(),
|
||||
"cols": cols,
|
||||
"slash_worker": None,
|
||||
"show_reasoning": _load_show_reasoning(),
|
||||
|
|
@ -3458,7 +3466,7 @@ def _init_session(sid: str, key: str, agent, history: list, cols: int = 80):
|
|||
# session (stdio for Ink, JSON-RPC WS for the dashboard sidebar).
|
||||
"transport": current_transport() or _stdio_transport,
|
||||
}
|
||||
db = _get_db()
|
||||
db = session_db if session_db is not None else _get_db()
|
||||
if db is not None:
|
||||
row = db.get_session(key)
|
||||
if row and row.get("cwd"):
|
||||
|
|
@ -4071,6 +4079,10 @@ def _(rid, params: dict) -> dict:
|
|||
target = found["id"]
|
||||
else:
|
||||
return _err(rid, 4007, "session not found")
|
||||
profile_resume_cwd = str(found.get("cwd") or "").strip() or _profile_configured_cwd(
|
||||
profile_home
|
||||
)
|
||||
|
||||
def _reuse_live_payload(sid: str, session: dict) -> dict:
|
||||
payload = _live_session_payload(
|
||||
sid,
|
||||
|
|
@ -4118,7 +4130,7 @@ def _(rid, params: dict) -> dict:
|
|||
lease.release()
|
||||
return _err(rid, 5000, f"resume failed: {e}")
|
||||
messages = _history_to_messages(history)
|
||||
cwd = os.getenv("TERMINAL_CWD", os.getcwd())
|
||||
cwd = profile_resume_cwd or os.getenv("TERMINAL_CWD", os.getcwd())
|
||||
now = time.time()
|
||||
# A delegated child mid-run emits no native session events of its own —
|
||||
# report its liveness from the relay registry so the window paints a
|
||||
|
|
@ -4261,7 +4273,24 @@ def _(rid, params: dict) -> dict:
|
|||
payload["resumed"] = target
|
||||
return _ok(rid, payload)
|
||||
try:
|
||||
_init_session(sid, target, agent, history, cols=cols)
|
||||
init_home_token = (
|
||||
set_hermes_home_override(str(profile_home))
|
||||
if profile_home is not None
|
||||
else None
|
||||
)
|
||||
try:
|
||||
_init_session(
|
||||
sid,
|
||||
target,
|
||||
agent,
|
||||
history,
|
||||
cols=cols,
|
||||
cwd=profile_resume_cwd,
|
||||
session_db=db,
|
||||
)
|
||||
finally:
|
||||
if init_home_token is not None:
|
||||
reset_hermes_home_override(init_home_token)
|
||||
if sid in _sessions:
|
||||
if stored_runtime_overrides.get("model_override") is not None:
|
||||
_sessions[sid]["model_override"] = stored_runtime_overrides[
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue