fix(status): render the session profile home
Let the shared status field builder accept an explicit owning home and have the multiplexed TUI/Desktop session.status path pass its session profile_home. Unscoped CLI/gateway callers keep the historical process-home fallback. Add focused coverage for a secondary-profile session and for the launch-profile fallback. Fixes #124500.
This commit is contained in:
@@ -13,6 +13,7 @@ They now all call :func:`build_status_fields`; a surface only adds its own heade
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
STATUS_STAMP = "%Y-%m-%d %H:%M"
|
||||
@@ -69,6 +70,7 @@ def build_status_fields(
|
||||
created_fallback: datetime | None = None,
|
||||
tokens: int | None = None,
|
||||
agent_running: bool = False,
|
||||
home: str | Path | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Common ``/status`` facts, pre-formatted for display.
|
||||
|
||||
@@ -76,6 +78,8 @@ def build_status_fields(
|
||||
(CLI ``self.model``, TUI metadata mirror, gateway's resolved route) and are also what a
|
||||
surface passes when it has no live agent. ``created`` / ``last_activity`` override the
|
||||
``meta`` row scan for surfaces whose session store is authoritative (gateway SessionEntry).
|
||||
``home`` is an explicit owning-profile path for multiplexed surfaces; omitted callers keep
|
||||
the process/current-profile lookup.
|
||||
"""
|
||||
from hermes_constants import display_hermes_home
|
||||
|
||||
@@ -89,7 +93,7 @@ def build_status_fields(
|
||||
row_title = meta.get("title") if title is None else title
|
||||
return {
|
||||
"session_id": str(session_id or ""),
|
||||
"path": display_hermes_home(),
|
||||
"path": display_hermes_home(Path(home) if home else None),
|
||||
"title": (row_title or "").strip(),
|
||||
"model": getattr(agent, "model", None) or model or "",
|
||||
"provider": getattr(agent, "provider", None) or provider or "",
|
||||
|
||||
75
tests/tui_gateway/test_status_profile_home.py
Normal file
75
tests/tui_gateway/test_status_profile_home.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""Profile-owned /status path rendering for multiplexed TUI/Desktop sessions (#124500)."""
|
||||
|
||||
import threading
|
||||
|
||||
from tui_gateway import server
|
||||
|
||||
|
||||
def _session(profile_home=None):
|
||||
row = {
|
||||
"session_key": "status-row",
|
||||
"history": [],
|
||||
"history_lock": threading.Lock(),
|
||||
"running": False,
|
||||
"agent": None,
|
||||
"created_at": 1.0,
|
||||
"last_active": 1.0,
|
||||
}
|
||||
if profile_home is not None:
|
||||
row["profile_home"] = str(profile_home)
|
||||
return row
|
||||
|
||||
|
||||
def test_session_status_path_uses_owning_profile_home(monkeypatch, tmp_path):
|
||||
launch_home = tmp_path / "profiles" / "launch"
|
||||
profile_home = tmp_path / "profiles" / "ember"
|
||||
launch_home.mkdir(parents=True)
|
||||
profile_home.mkdir(parents=True)
|
||||
monkeypatch.setenv("HERMES_HOME", str(launch_home))
|
||||
|
||||
class LaunchDB:
|
||||
def get_session(self, _key):
|
||||
raise AssertionError("secondary-profile status must not read the launch DB")
|
||||
|
||||
class ProfileDB:
|
||||
def __init__(self, db_path=None):
|
||||
assert str(db_path) == str(profile_home / "state.db")
|
||||
|
||||
def get_session(self, key):
|
||||
return {"id": key, "title": "owned", "started_at": 1}
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
server._sessions["status-profile-home"] = _session(profile_home)
|
||||
monkeypatch.setattr(server, "_get_db", lambda: LaunchDB())
|
||||
monkeypatch.setattr("hermes_state_registry.acquire", ProfileDB)
|
||||
try:
|
||||
resp = server.handle_request(
|
||||
{"id": "1", "method": "session.status", "params": {"session_id": "status-profile-home"}}
|
||||
)
|
||||
output = resp["result"]["output"]
|
||||
assert f"Path: {profile_home}" in output
|
||||
assert f"Path: {launch_home}" not in output
|
||||
finally:
|
||||
server._sessions.pop("status-profile-home", None)
|
||||
|
||||
|
||||
def test_session_status_path_without_profile_home_keeps_launch_home(monkeypatch, tmp_path):
|
||||
launch_home = tmp_path / "launch"
|
||||
launch_home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(launch_home))
|
||||
|
||||
class LaunchDB:
|
||||
def get_session(self, key):
|
||||
return {"id": key, "title": "launch", "started_at": 1}
|
||||
|
||||
server._sessions["status-launch-home"] = _session()
|
||||
monkeypatch.setattr(server, "_get_db", lambda: LaunchDB())
|
||||
try:
|
||||
resp = server.handle_request(
|
||||
{"id": "1", "method": "session.status", "params": {"session_id": "status-launch-home"}}
|
||||
)
|
||||
assert f"Path: {launch_home}" in resp["result"]["output"]
|
||||
finally:
|
||||
server._sessions.pop("status-launch-home", None)
|
||||
@@ -1843,6 +1843,7 @@ def _(rid, params: dict, session: dict) -> dict:
|
||||
model=mirror.get("model") or getattr(live_agent, "model", None),
|
||||
provider=mirror.get("provider") or getattr(live_agent, "provider", None),
|
||||
tokens=_session_usage_snapshot(session).get("total"), agent_running=bool(session.get("running")),
|
||||
home=session.get("profile_home"),
|
||||
)
|
||||
project = _project_info_for_cwd(_display_session_cwd(session))
|
||||
lines = [
|
||||
|
||||
Reference in New Issue
Block a user