fix(conversation_store,admin,cli): keep session when file lags db, sort pty by recency
This commit is contained in:
@@ -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():
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
{% block content %}
|
||||
<h2>Live PTY sessions</h2>
|
||||
<p class="muted">
|
||||
Each row is a running <code>claude</code> subprocess. Open one to see what's
|
||||
currently rendered on its TUI and (if needed) type into it directly.
|
||||
Each row is a running <code>claude</code> subprocess, most recently used first.
|
||||
Open one to see what's currently rendered on its TUI and (if needed) type into
|
||||
it directly. Sessions idle past the agent's TTL are terminated automatically.
|
||||
</p>
|
||||
|
||||
{% if sessions %}
|
||||
@@ -15,6 +16,8 @@
|
||||
<tr>
|
||||
<th>Session ID</th>
|
||||
<th>Agent</th>
|
||||
<th>Idle</th>
|
||||
<th>Age</th>
|
||||
<th>PID</th>
|
||||
<th>Buffer</th>
|
||||
<th></th>
|
||||
@@ -25,6 +28,8 @@
|
||||
<tr>
|
||||
<td><code>{{ s.session_id }}</code></td>
|
||||
<td>{{ s.agent }}</td>
|
||||
<td>{{ s.idle }}</td>
|
||||
<td class="muted">{{ s.age }}</td>
|
||||
<td><span class="pill">{{ s.pid or "?" }}</span></td>
|
||||
<td>{{ s.buffer_size }} bytes</td>
|
||||
<td>
|
||||
|
||||
Reference in New Issue
Block a user