fix(conversation_store,admin,cli): keep session when file lags db, sort pty by recency

This commit is contained in:
hh
2026-07-26 00:25:07 +02:00
parent d2981116d4
commit 90fe92d014
7 changed files with 113 additions and 7 deletions
@@ -567,13 +567,19 @@ def _collect_pty_sessions(runtime: GatewayRuntime) -> list[dict[str, Any]]:
(currently only ``ClaudeCodeBackendAdapter``). Other backend types
are quietly skipped — the admin terminal viewer only makes sense for
PTY-backed agents.
Sorted most-recently-used first. The underlying mapping is keyed by
conversation fingerprint and reshuffled on every pool hit, so its
iteration order carries no meaning a human could act on.
"""
now = time.time()
out: list[dict[str, Any]] = []
for agent_name, backend in runtime.backends.items():
live = getattr(backend, "live_sessions", None)
if not isinstance(live, dict):
continue
for session_id, pty in live.items():
last_used = getattr(pty, "last_activity_at", None) or now
out.append(
{
"agent": agent_name,
@@ -582,11 +588,28 @@ def _collect_pty_sessions(runtime: GatewayRuntime) -> list[dict[str, Any]]:
"buffer_size": len(pty.captured_output())
if hasattr(pty, "captured_output")
else 0,
"last_used": last_used,
"idle": _humanize_duration(now - last_used),
"age": _humanize_duration(
now - (getattr(pty, "created_at", None) or now)
),
}
)
out.sort(key=lambda s: s["last_used"], reverse=True)
return out
def _humanize_duration(seconds: float) -> str:
"""Render a duration as the coarsest unit that still reads precisely."""
secs = max(0, int(seconds))
if secs < 60:
return f"{secs}s"
if secs < 3600:
return f"{secs // 60}m {secs % 60}s"
hours, rem = divmod(secs, 3600)
return f"{hours}h {rem // 60}m"
def _find_pty(runtime: GatewayRuntime, session_id: str) -> Any:
"""Locate a live PTY by its claude session_id, across all backends."""
for backend in runtime.backends.values():