hermes-agent/tests/hermes_cli/test_cli_active_session_limit.py
Brooklyn Nicholson 78aeeab8d1 feat(sessions): say which surfaces hold the active-session slots
The cap is shared across CLI, desktop/TUI and the messaging gateway, so the
surface that gets rejected is rarely the one holding the slots. The rejection
read "Hermes is at the active session limit (5/5). Try again when another
session finishes." while every slot was an idle desktop tab, which took
filesystem access to work out.

Name the holders in the message, and show slot usage plus each holder in
`hermes status`. Both are inert when max_concurrent_sessions is unset, which
is the default. The gateway's duplicate copy of the message now reuses the
shared helper.
2026-07-28 12:11:52 -05:00

41 lines
1.3 KiB
Python

from cli import HermesCLI
from hermes_cli.active_sessions import (
active_session_registry_snapshot,
try_acquire_active_session,
)
def test_cli_claim_active_session_respects_global_limit(tmp_path, monkeypatch):
monkeypatch.setenv("HERMES_HOME", str(tmp_path / ".hermes"))
cfg = {"max_concurrent_sessions": 1}
held, message = try_acquire_active_session(
session_id="held-session",
surface="tui",
config=cfg,
)
assert message is None
assert held is not None
cli = object.__new__(HermesCLI)
cli.session_id = "new-cli-session"
cli.config = cfg
cli._active_session_lease = None
printed: list[str] = []
cli._console_print = lambda text: printed.append(text)
try:
assert cli._claim_active_session("cli") is False
assert len(printed) == 1
assert "active session limit (1/1)" in printed[0]
# Names the holding surface ("tui"), not the blocked one.
assert "Held by: tui" in printed[0]
held.release()
assert cli._claim_active_session("cli") is True
assert [entry["session_id"] for entry in active_session_registry_snapshot()] == [
"new-cli-session"
]
finally:
held.release()
cli._release_active_session()