Keep resumed profile cwd scoped to profile DB

This commit is contained in:
dsad 2026-06-14 02:31:17 +03:00 committed by Teknium
parent 4936a49a0c
commit d842155da1
2 changed files with 124 additions and 7 deletions

View file

@ -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

View file

@ -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[