mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(tui): /resume picker shows telegram/discord/etc sessions
Reported during TUI v2 blitz retest: /resume modal only surfaced tui/cli rows, even though `hermes --tui --resume <id>` with a pasted telegram session id works fine. The handler double-fetched with explicit `source="tui"` and `source="cli"` filters and dropped everything else on the floor. Drop the filter — list_sessions_rich(source=None) already excludes child sessions (subagents, compression continuations) via its default, and users want to resume messenger sessions from inside the TUI. Adds gateway regression coverage.
This commit is contained in:
parent
35a4b093d8
commit
0dfb7b8a0d
2 changed files with 90 additions and 6 deletions
84
tests/gateway/test_session_list_all_sources.py
Normal file
84
tests/gateway/test_session_list_all_sources.py
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
"""Regression test for the TUI gateway's ``session.list`` handler.
|
||||
|
||||
Reported during the TUI v2 blitz retest: the ``/resume`` modal inside a
|
||||
TUI session only surfaced ``tui``/``cli`` rows — telegram/discord/whatsapp
|
||||
sessions stayed hidden even though the user could still paste the id
|
||||
directly into ``hermes --tui --resume <id>`` and get a working session.
|
||||
|
||||
The fix removes the adapter-kind filter so every session the DB surfaces
|
||||
appears in the picker, sorted by ``started_at`` like before.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import types
|
||||
|
||||
from tui_gateway import server
|
||||
|
||||
|
||||
class _StubDB:
|
||||
def __init__(self, rows):
|
||||
self.rows = rows
|
||||
self.calls: list[dict] = []
|
||||
|
||||
def list_sessions_rich(self, **kwargs):
|
||||
self.calls.append(kwargs)
|
||||
return list(self.rows)
|
||||
|
||||
|
||||
def _call(limit: int = 20):
|
||||
return server.handle_request({
|
||||
"id": "1",
|
||||
"method": "session.list",
|
||||
"params": {"limit": limit},
|
||||
})
|
||||
|
||||
|
||||
def test_session_list_does_not_filter_by_source(monkeypatch):
|
||||
rows = [
|
||||
{"id": "tui-1", "source": "tui", "title": "a", "preview": "", "started_at": 3, "message_count": 1},
|
||||
{"id": "tg-1", "source": "telegram", "title": "b", "preview": "", "started_at": 2, "message_count": 1},
|
||||
{"id": "cli-1", "source": "cli", "title": "c", "preview": "", "started_at": 1, "message_count": 1},
|
||||
]
|
||||
db = _StubDB(rows)
|
||||
monkeypatch.setattr(server, "_get_db", lambda: db)
|
||||
|
||||
resp = _call(limit=10)
|
||||
|
||||
assert "result" in resp, resp
|
||||
assert len(db.calls) == 1
|
||||
assert db.calls[0].get("source") is None, db.calls[0]
|
||||
assert db.calls[0].get("limit") == 10
|
||||
|
||||
kinds = [s["source"] for s in resp["result"]["sessions"]]
|
||||
assert "telegram" in kinds and "tui" in kinds and "cli" in kinds, kinds
|
||||
|
||||
|
||||
def test_session_list_preserves_ordering(monkeypatch):
|
||||
rows = [
|
||||
{"id": "newest", "source": "telegram", "title": "", "preview": "", "started_at": 5, "message_count": 1},
|
||||
{"id": "middle", "source": "tui", "title": "", "preview": "", "started_at": 3, "message_count": 1},
|
||||
{"id": "oldest", "source": "discord", "title": "", "preview": "", "started_at": 1, "message_count": 1},
|
||||
]
|
||||
monkeypatch.setattr(server, "_get_db", lambda: _StubDB(rows))
|
||||
|
||||
resp = _call()
|
||||
ids = [s["id"] for s in resp["result"]["sessions"]]
|
||||
|
||||
assert ids == ["newest", "middle", "oldest"]
|
||||
|
||||
|
||||
def test_session_list_surfaces_missing_fields_as_empty(monkeypatch):
|
||||
rows = [{"id": "bare", "source": "whatsapp"}]
|
||||
monkeypatch.setattr(server, "_get_db", lambda: _StubDB(rows))
|
||||
|
||||
sess = _call()["result"]["sessions"][0]
|
||||
|
||||
assert sess == {
|
||||
"id": "bare",
|
||||
"title": "",
|
||||
"preview": "",
|
||||
"started_at": 0,
|
||||
"message_count": 0,
|
||||
"source": "whatsapp",
|
||||
}
|
||||
|
|
@ -1231,12 +1231,12 @@ def _(rid, params: dict) -> dict:
|
|||
@method("session.list")
|
||||
def _(rid, params: dict) -> dict:
|
||||
try:
|
||||
db = _get_db()
|
||||
# Show both TUI and CLI sessions — TUI is the successor to the CLI,
|
||||
# so users expect to resume their old CLI sessions here too.
|
||||
tui = db.list_sessions_rich(source="tui", limit=params.get("limit", 20))
|
||||
cli = db.list_sessions_rich(source="cli", limit=params.get("limit", 20))
|
||||
rows = sorted(tui + cli, key=lambda s: s.get("started_at") or 0, reverse=True)[:params.get("limit", 20)]
|
||||
# Show sessions from every adapter — users resume telegram/discord/etc
|
||||
# sessions by pasting the id directly, so the picker should surface them
|
||||
# too. Children (subagents/compression runs) stay filtered out via the
|
||||
# hermes_state default.
|
||||
limit = params.get("limit", 20)
|
||||
rows = _get_db().list_sessions_rich(source=None, limit=limit)
|
||||
return _ok(rid, {"sessions": [
|
||||
{"id": s["id"], "title": s.get("title") or "", "preview": s.get("preview") or "",
|
||||
"started_at": s.get("started_at") or 0, "message_count": s.get("message_count") or 0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue