fix(tui): -c resume, ctrl z, pasting updates, exit summary, session fix
This commit is contained in:
119
tests/hermes_cli/test_tui_resume_flow.py
Normal file
119
tests/hermes_cli/test_tui_resume_flow.py
Normal file
@@ -0,0 +1,119 @@
|
||||
from argparse import Namespace
|
||||
import sys
|
||||
import types
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _args(**overrides):
|
||||
base = {
|
||||
"continue_last": None,
|
||||
"resume": None,
|
||||
"tui": True,
|
||||
}
|
||||
base.update(overrides)
|
||||
return Namespace(**base)
|
||||
|
||||
|
||||
def test_cmd_chat_tui_continue_uses_latest_tui_session(monkeypatch):
|
||||
import hermes_cli.main as main_mod
|
||||
|
||||
calls = []
|
||||
captured = {}
|
||||
|
||||
def fake_resolve_last(source="cli"):
|
||||
calls.append(source)
|
||||
return "20260408_235959_a1b2c3" if source == "tui" else None
|
||||
|
||||
def fake_launch(resume_session_id=None):
|
||||
captured["resume"] = resume_session_id
|
||||
raise SystemExit(0)
|
||||
|
||||
monkeypatch.setattr(main_mod, "_resolve_last_session", fake_resolve_last)
|
||||
monkeypatch.setattr(main_mod, "_resolve_session_by_name_or_id", lambda val: val)
|
||||
monkeypatch.setattr(main_mod, "_launch_tui", fake_launch)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
main_mod.cmd_chat(_args(continue_last=True))
|
||||
|
||||
assert calls == ["tui"]
|
||||
assert captured["resume"] == "20260408_235959_a1b2c3"
|
||||
|
||||
|
||||
def test_cmd_chat_tui_continue_falls_back_to_latest_cli_session(monkeypatch):
|
||||
import hermes_cli.main as main_mod
|
||||
|
||||
calls = []
|
||||
captured = {}
|
||||
|
||||
def fake_resolve_last(source="cli"):
|
||||
calls.append(source)
|
||||
if source == "tui":
|
||||
return None
|
||||
if source == "cli":
|
||||
return "20260408_235959_d4e5f6"
|
||||
return None
|
||||
|
||||
def fake_launch(resume_session_id=None):
|
||||
captured["resume"] = resume_session_id
|
||||
raise SystemExit(0)
|
||||
|
||||
monkeypatch.setattr(main_mod, "_resolve_last_session", fake_resolve_last)
|
||||
monkeypatch.setattr(main_mod, "_resolve_session_by_name_or_id", lambda val: val)
|
||||
monkeypatch.setattr(main_mod, "_launch_tui", fake_launch)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
main_mod.cmd_chat(_args(continue_last=True))
|
||||
|
||||
assert calls == ["tui", "cli"]
|
||||
assert captured["resume"] == "20260408_235959_d4e5f6"
|
||||
|
||||
|
||||
def test_cmd_chat_tui_resume_resolves_title_before_launch(monkeypatch):
|
||||
import hermes_cli.main as main_mod
|
||||
|
||||
captured = {}
|
||||
|
||||
def fake_launch(resume_session_id=None):
|
||||
captured["resume"] = resume_session_id
|
||||
raise SystemExit(0)
|
||||
|
||||
monkeypatch.setattr(main_mod, "_resolve_session_by_name_or_id", lambda val: "20260409_000000_aa11bb")
|
||||
monkeypatch.setattr(main_mod, "_launch_tui", fake_launch)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
main_mod.cmd_chat(_args(resume="my t0p session"))
|
||||
|
||||
assert captured["resume"] == "20260409_000000_aa11bb"
|
||||
|
||||
|
||||
def test_print_tui_exit_summary_includes_resume_and_token_totals(monkeypatch, capsys):
|
||||
import hermes_cli.main as main_mod
|
||||
|
||||
class _FakeDB:
|
||||
def get_session(self, session_id):
|
||||
assert session_id == "20260409_000001_abc123"
|
||||
return {
|
||||
"message_count": 2,
|
||||
"input_tokens": 10,
|
||||
"output_tokens": 6,
|
||||
"cache_read_tokens": 2,
|
||||
"cache_write_tokens": 2,
|
||||
"reasoning_tokens": 1,
|
||||
}
|
||||
|
||||
def get_session_title(self, _session_id):
|
||||
return "demo title"
|
||||
|
||||
def close(self):
|
||||
return None
|
||||
|
||||
monkeypatch.setitem(sys.modules, "hermes_state", types.SimpleNamespace(SessionDB=lambda: _FakeDB()))
|
||||
|
||||
main_mod._print_tui_exit_summary("20260409_000001_abc123")
|
||||
out = capsys.readouterr().out
|
||||
|
||||
assert "Resume this session with:" in out
|
||||
assert "hermes --tui --resume 20260409_000001_abc123" in out
|
||||
assert 'hermes --tui -c "demo title"' in out
|
||||
assert "Tokens: 21 (in 10, out 6, cache 4, reasoning 1)" in out
|
||||
@@ -151,6 +151,52 @@ def test_sess_found(server):
|
||||
assert err is None
|
||||
|
||||
|
||||
# ── session.resume payload ────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_session_resume_returns_hydrated_messages(server, monkeypatch):
|
||||
class _DB:
|
||||
def get_session(self, _sid):
|
||||
return {"id": "20260409_010101_abc123"}
|
||||
|
||||
def get_session_by_title(self, _title):
|
||||
return None
|
||||
|
||||
def reopen_session(self, _sid):
|
||||
return None
|
||||
|
||||
def get_messages(self, _sid):
|
||||
return [
|
||||
{"role": "user", "content": "hello"},
|
||||
{"role": "assistant", "content": "yo"},
|
||||
{"role": "tool", "content": "searched"},
|
||||
{"role": "assistant", "content": " "},
|
||||
{"role": "assistant", "content": None},
|
||||
{"role": "narrator", "content": "skip"},
|
||||
]
|
||||
|
||||
monkeypatch.setattr(server, "_get_db", lambda: _DB())
|
||||
monkeypatch.setattr(server, "_make_agent", lambda sid, key, session_id=None: object())
|
||||
monkeypatch.setattr(server, "_init_session", lambda sid, key, agent, history, cols=80: None)
|
||||
monkeypatch.setattr(server, "_session_info", lambda _agent: {"model": "test/model"})
|
||||
|
||||
resp = server.handle_request(
|
||||
{
|
||||
"id": "r1",
|
||||
"method": "session.resume",
|
||||
"params": {"session_id": "20260409_010101_abc123", "cols": 100},
|
||||
}
|
||||
)
|
||||
|
||||
assert "error" not in resp
|
||||
assert resp["result"]["message_count"] == 3
|
||||
assert resp["result"]["messages"] == [
|
||||
{"role": "user", "text": "hello"},
|
||||
{"role": "assistant", "text": "yo"},
|
||||
{"role": "tool", "text": "searched"},
|
||||
]
|
||||
|
||||
|
||||
# ── Config I/O ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user