mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
fix(gateway): make bg-process reset TTL configurable + surface session-scoped processes
Follow-up to the cherry-picked #29212 (#29177): - Promote the 24h stale-process threshold to config.yaml (session_reset.bg_process_max_age_hours) instead of a hardcoded constant. 0 disables the cutoff (legacy: any live process blocks reset). Wired through GatewayConfig.default_reset_policy in gateway/run.py. - Bug 2: process(action=list) now resolves the gateway session_key from the contextvar and surfaces session-scoped background processes (a forgotten preview server under a different task), flagged session_scoped — so the agent/user can discover and kill the blocker. Previously the task-scoped list returned [] and the blocker was invisible. - Tests: config round-trip for the new field, cross-task list visibility. - Docs: messaging session-reset section.
This commit is contained in:
parent
33d8b66d5b
commit
a1ac6baac4
6 changed files with 101 additions and 13 deletions
|
|
@ -138,26 +138,31 @@ class TestGetConnectedPlatforms:
|
|||
|
||||
class TestSessionResetPolicy:
|
||||
def test_roundtrip(self):
|
||||
policy = SessionResetPolicy(mode="idle", at_hour=6, idle_minutes=120)
|
||||
policy = SessionResetPolicy(mode="idle", at_hour=6, idle_minutes=120,
|
||||
bg_process_max_age_hours=48)
|
||||
d = policy.to_dict()
|
||||
restored = SessionResetPolicy.from_dict(d)
|
||||
assert restored.mode == "idle"
|
||||
assert restored.at_hour == 6
|
||||
assert restored.idle_minutes == 120
|
||||
assert restored.bg_process_max_age_hours == 48
|
||||
|
||||
def test_defaults(self):
|
||||
policy = SessionResetPolicy()
|
||||
assert policy.mode == "both"
|
||||
assert policy.at_hour == 4
|
||||
assert policy.idle_minutes == 1440
|
||||
assert policy.bg_process_max_age_hours == 24
|
||||
|
||||
def test_from_dict_treats_null_values_as_defaults(self):
|
||||
restored = SessionResetPolicy.from_dict(
|
||||
{"mode": None, "at_hour": None, "idle_minutes": None}
|
||||
{"mode": None, "at_hour": None, "idle_minutes": None,
|
||||
"bg_process_max_age_hours": None}
|
||||
)
|
||||
assert restored.mode == "both"
|
||||
assert restored.at_hour == 4
|
||||
assert restored.idle_minutes == 1440
|
||||
assert restored.bg_process_max_age_hours == 24
|
||||
|
||||
def test_from_dict_coerces_quoted_false_notify(self):
|
||||
restored = SessionResetPolicy.from_dict({"notify": "false"})
|
||||
|
|
|
|||
|
|
@ -416,6 +416,34 @@ class TestListSessions:
|
|||
assert len(result) == 1
|
||||
assert result[0]["session_id"] == "proc_1"
|
||||
|
||||
def test_session_key_surfaces_cross_task_processes(self, registry):
|
||||
"""A bg process under the same gateway session but a DIFFERENT task is
|
||||
surfaced when session_key is passed, and flagged session_scoped (#29177).
|
||||
"""
|
||||
# Current turn's task = "t_now"; forgotten preview server = "t_old"
|
||||
# but both share gateway session_key "gw1".
|
||||
own = _make_session(sid="proc_own", task_id="t_now")
|
||||
own.session_key = "gw1"
|
||||
forgotten = _make_session(sid="proc_forgotten", task_id="t_old")
|
||||
forgotten.session_key = "gw1"
|
||||
other = _make_session(sid="proc_other", task_id="t_x")
|
||||
other.session_key = "gw_other"
|
||||
registry._running[own.id] = own
|
||||
registry._running[forgotten.id] = forgotten
|
||||
registry._running[other.id] = other
|
||||
|
||||
# Task-only (legacy) view sees just the current task's process.
|
||||
legacy = registry.list_sessions(task_id="t_now")
|
||||
assert {r["session_id"] for r in legacy} == {"proc_own"}
|
||||
|
||||
# With session_key, the forgotten process under the same gateway
|
||||
# session is surfaced and flagged; the unrelated session is not.
|
||||
result = registry.list_sessions(task_id="t_now", session_key="gw1")
|
||||
by_id = {r["session_id"]: r for r in result}
|
||||
assert set(by_id) == {"proc_own", "proc_forgotten"}
|
||||
assert by_id["proc_forgotten"].get("session_scoped") is True
|
||||
assert "session_scoped" not in by_id["proc_own"]
|
||||
|
||||
def test_list_entry_fields(self, registry):
|
||||
s = _make_session(output="preview text")
|
||||
registry._running[s.id] = s
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue