Compare commits

...

1 Commits

Author SHA1 Message Date
kshitijk4poor
a456b50a3f fix(cli): surface recent sessions inside /history and /resume
When /history is used in an empty chat, show a table of recent
resumable sessions instead of a dead-end message. When /resume is
called with no argument, show the same table with resume guidance.

- Add _list_recent_sessions() and _show_recent_sessions() to HermesCLI
- Remove redundant exclude_sources (already filtered by source='cli')
- Center the table header properly

Cherry-picked from PR #4448.
2026-04-03 00:58:45 -07:00
2 changed files with 103 additions and 1 deletions

50
cli.py
View File

@@ -3052,10 +3052,56 @@ class HermesCLI:
print(f" Config File: {config_path} {config_status}")
print()
def _list_recent_sessions(self, limit: int = 10) -> list[dict[str, Any]]:
"""Return recent CLI sessions for in-chat browsing/resume affordances."""
if not self._session_db:
return []
try:
sessions = self._session_db.list_sessions_rich(
source="cli",
limit=limit,
)
except Exception:
return []
return [s for s in sessions if s.get("id") != self.session_id]
def _show_recent_sessions(self, *, reason: str = "history", limit: int = 10) -> bool:
"""Render recent sessions inline from the active chat TUI.
Returns True when something was shown, False if no session list was available.
"""
sessions = self._list_recent_sessions(limit=limit)
if not sessions:
return False
from hermes_cli.main import _relative_time
print()
print("+" + "-" * 86 + "+")
print("|" + "Recent Sessions".center(86) + "|")
print("+" + "-" * 86 + "+")
print(f" {'Title':<30} {'Preview':<30} {'Last Active':<12} ID")
print(f" {'' * 30} {'' * 30} {'' * 12} {'' * 18}")
for session in sessions:
title = (session.get("title") or "")[:30]
preview = (session.get("preview") or "")[:30]
last_active = _relative_time(session.get("last_active"))
print(f" {title:<30} {preview:<30} {last_active:<12} {session['id']}")
print()
if reason == "history":
print("(._.) No messages in the current chat yet.")
print(" Above are recent sessions you can resume with /resume <session id or title>.")
else:
print(" Use /resume <session id or title> to switch to one of these sessions.")
print()
return True
def show_history(self):
"""Display conversation history."""
if not self.conversation_history:
print("(._.) No conversation history yet.")
if not self._show_recent_sessions(reason="history"):
print("(._.) No conversation history yet.")
return
preview_limit = 400
@@ -3180,6 +3226,8 @@ class HermesCLI:
if not target:
_cprint(" Usage: /resume <session_id_or_title>")
if self._show_recent_sessions(reason="resume"):
return
_cprint(" Tip: Use /history or `hermes sessions list` to find sessions.")
return

View File

@@ -191,6 +191,60 @@ class TestHistoryDisplay:
assert "A" * 250 in output
assert "A" * 250 + "..." not in output
def test_history_shows_recent_sessions_when_current_chat_is_empty(self, capsys):
cli = _make_cli()
cli.session_id = "current"
cli._session_db = MagicMock()
cli._session_db.list_sessions_rich.return_value = [
{
"id": "current",
"title": "Current",
"preview": "Current preview",
"last_active": 0,
},
{
"id": "20260401_201329_d85961",
"title": "Checking Running Hermes Agent",
"preview": "check running gateways for hermes agent",
"last_active": 0,
},
]
cli.show_history()
output = capsys.readouterr().out
assert "Recent Sessions" in output
assert "Checking Running Hermes Agent" in output
assert "20260401_201329_d85961" in output
assert "No messages in the current chat yet." in output
assert "Current preview" not in output
def test_resume_without_target_lists_recent_sessions(self, capsys):
cli = _make_cli()
cli.session_id = "current"
cli._session_db = MagicMock()
cli._session_db.list_sessions_rich.return_value = [
{
"id": "current",
"title": "Current",
"preview": "Current preview",
"last_active": 0,
},
{
"id": "20260401_201329_d85961",
"title": "Checking Running Hermes Agent",
"preview": "check running gateways for hermes agent",
"last_active": 0,
},
]
cli._handle_resume_command("/resume")
output = capsys.readouterr().out
assert "Recent Sessions" in output
assert "Checking Running Hermes Agent" in output
assert "Use /resume <session id or title> to switch" in output
class TestRootLevelProviderOverride:
"""Root-level provider/base_url in config.yaml must NOT override model.provider."""