Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion gateway/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -4972,6 +4972,21 @@ async def _handle_profile_command(self, event: MessageEvent) -> str:

return "\n".join(lines)

def _status_total_tokens(self, session_entry: "SessionEntry") -> int:
"""Return total tokens for /status, preferring SQLite session stats."""
if self._session_db:
try:
row = self._session_db.get_session(session_entry.session_id)
except Exception:
row = None
if row:
input_tokens = int(row.get("input_tokens") or 0)
output_tokens = int(row.get("output_tokens") or 0)
cache_read_tokens = int(row.get("cache_read_tokens") or 0)
cache_write_tokens = int(row.get("cache_write_tokens") or 0)
return input_tokens + output_tokens + cache_read_tokens + cache_write_tokens
return int(getattr(session_entry, "total_tokens", 0) or 0)

async def _handle_status_command(self, event: MessageEvent) -> str:
"""Handle /status command."""
source = event.source
Expand All @@ -4990,6 +5005,8 @@ async def _handle_status_command(self, event: MessageEvent) -> str:
except Exception:
title = None

total_tokens = self._status_total_tokens(session_entry)

lines = [
"πŸ“Š **Hermes Gateway Status**",
"",
Expand All @@ -5000,7 +5017,7 @@ async def _handle_status_command(self, event: MessageEvent) -> str:
lines.extend([
f"**Created:** {session_entry.created_at.strftime('%Y-%m-%d %H:%M')}",
f"**Last Activity:** {session_entry.updated_at.strftime('%Y-%m-%d %H:%M')}",
f"**Tokens:** {session_entry.total_tokens:,}",
f"**Tokens:** {total_tokens:,}",
f"**Agent Running:** {'Yes ⚑' if is_running else 'No'}",
"",
f"**Connected Platforms:** {', '.join(connected_platforms)}",
Expand Down
26 changes: 26 additions & 0 deletions tests/gateway/test_status_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def _make_runner(session_entry: SessionEntry):
runner._pending_messages = {}
runner._pending_approvals = {}
runner._session_db = MagicMock()
runner._session_db.get_session.return_value = None
runner._session_db.get_session_title.return_value = None
runner._reasoning_config = None
runner._provider_routing = {}
Expand Down Expand Up @@ -113,6 +114,31 @@ async def test_status_command_includes_session_title_when_present():
assert "**Title:** My titled session" in result


@pytest.mark.asyncio
async def test_status_command_prefers_sqlite_token_counts_over_session_store_entry():
session_entry = SessionEntry(
session_key=build_session_key(_make_source()),
session_id="sess-1",
created_at=datetime.now(),
updated_at=datetime.now(),
platform=Platform.TELEGRAM,
chat_type="dm",
total_tokens=0,
)
runner = _make_runner(session_entry)
runner._session_db.get_session.return_value = {
"id": "sess-1",
"input_tokens": 120,
"output_tokens": 45,
"cache_read_tokens": 30,
"cache_write_tokens": 5,
}

result = await runner._handle_message(_make_event("/status"))

assert "**Tokens:** 200" in result


@pytest.mark.asyncio
async def test_agents_command_reports_active_agents_and_processes(monkeypatch):
session_key = build_session_key(_make_source())
Expand Down