diff --git a/gateway/run.py b/gateway/run.py index 345a69e100c92..fd1d62feb1028 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -11964,7 +11964,8 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew logger.warning( "Session stall detected: session=%s idle=%.0fs " "(timeout=%.0fs, ~%d min); pending inbound present " - "| last_activity=%s | provenance=%s", + "| last_activity=%s | provenance=%s " + "(agent.session_stall_timeout)", session_key, idle_seconds, timeout_seconds, diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 5de050dd49c8c..98874824c196c 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -944,21 +944,15 @@ def _termux_should_prefetch_update_check() -> bool: def _relative_time(ts) -> str: - """Format a timestamp as relative time (e.g., '2h ago', 'yesterday').""" - if not ts: - return "?" - delta = _time.time() - ts - if delta < 60: - return "just now" - if delta < 3600: - return f"{int(delta / 60)}m ago" - if delta < 86400: - return f"{int(delta / 3600)}h ago" - if delta < 172800: - return "yesterday" - if delta < 604800: - return f"{int(delta / 86400)}d ago" - return datetime.fromtimestamp(ts).strftime("%Y-%m-%d") + """Format a timestamp as relative time (e.g., '2h ago', 'yesterday'). + + Thin wrapper kept for backward compatibility; the implementation lives + in :mod:`hermes_cli.timefmt` so lightweight consumers don't have to + import the whole CLI surface. + """ + from hermes_cli.timefmt import relative_time + + return relative_time(ts) def _has_any_provider_configured() -> bool: diff --git a/hermes_cli/status.py b/hermes_cli/status.py index 8e0c4154fa9c2..20b306fec1c74 100644 --- a/hermes_cli/status.py +++ b/hermes_cli/status.py @@ -65,9 +65,9 @@ def _format_iso_timestamp(value) -> str: def _format_relative_ts(ts: float) -> str: """Format an epoch timestamp as a short relative age for status output.""" - from hermes_cli.main import _relative_time + from hermes_cli.timefmt import relative_time - return _relative_time(ts) + return relative_time(ts) def _configured_model_label(config: dict) -> str: diff --git a/hermes_cli/timefmt.py b/hermes_cli/timefmt.py new file mode 100644 index 0000000000000..cf32c926d8bfb --- /dev/null +++ b/hermes_cli/timefmt.py @@ -0,0 +1,30 @@ +"""Small shared time-formatting helpers for CLI output. + +Public home for helpers that used to live as private functions on +``hermes_cli.main`` — importing that module drags in the whole CLI +surface, which lightweight consumers (``hermes status``, dump tooling) +should not pay for. +""" + +from __future__ import annotations + +import time as _time +from datetime import datetime + + +def relative_time(ts) -> str: + """Format a timestamp as relative time (e.g., '2h ago', 'yesterday').""" + if not ts: + return "?" + delta = _time.time() - ts + if delta < 60: + return "just now" + if delta < 3600: + return f"{int(delta / 60)}m ago" + if delta < 86400: + return f"{int(delta / 3600)}h ago" + if delta < 172800: + return "yesterday" + if delta < 604800: + return f"{int(delta / 86400)}d ago" + return datetime.fromtimestamp(ts).strftime("%Y-%m-%d") diff --git a/hermes_state.py b/hermes_state.py index 370524f3f7de7..e7fc109980aaf 100644 --- a/hermes_state.py +++ b/hermes_state.py @@ -188,7 +188,6 @@ def _workspace_key_clause(key: str) -> Tuple[str, List[str]]: ) - def _collect_delegate_child_ids(conn, parent_ids: List[str]) -> List[str]: """Delegate-subagent ids to cascade-delete with *parent_ids*. diff --git a/tests/agent/test_session_activity.py b/tests/agent/test_session_activity.py index 306a89846bff0..7d6726a0f1e75 100644 --- a/tests/agent/test_session_activity.py +++ b/tests/agent/test_session_activity.py @@ -3,6 +3,7 @@ from types import SimpleNamespace from agent.session_activity import ( + ACTIVITY_DESCRIPTION_MAX, ActivityProvenance, bound_activity_description, build_activity_snapshot, @@ -12,9 +13,9 @@ from agent.session_activity import ( def test_bound_activity_description_truncates(): - long = "x" * 200 + long = "x" * (ACTIVITY_DESCRIPTION_MAX + 80) out = bound_activity_description(long) - assert len(out) == 120 + assert len(out) == ACTIVITY_DESCRIPTION_MAX assert out.endswith("…")