56 lines
2.4 KiB
Python
56 lines
2.4 KiB
Python
"""Read-only mobile subagent views, scoped to the invoking live session."""
|
|
import time
|
|
from pathlib import Path
|
|
|
|
|
|
def owned_records(session_id, transport, session, *, include_lineage=False):
|
|
from tools.delegate_tool import _active_subagents, _active_subagents_lock, _owns_subagent_record
|
|
if transport is None or session is None:
|
|
return []
|
|
with _active_subagents_lock:
|
|
records = [dict(row) for row in _active_subagents.values()]
|
|
return [row for row in records
|
|
if (row.get("owner_session_id") == session_id
|
|
and row.get("owner_transport") is transport
|
|
and row.get("owner_session_record") is session)
|
|
or (include_lineage and _owns_subagent_record(row, session.get("agent")))]
|
|
|
|
|
|
def roster(records):
|
|
fields = ("subagent_id", "parent_id", "depth", "goal", "delegation_id", "model",
|
|
"started_at", "status", "tool_count", "last_tool", "accepting_steer")
|
|
rows = []
|
|
for record in records:
|
|
row = {key: record[key] for key in fields if key in record}
|
|
started = record.get("started_at")
|
|
if isinstance(started, (int, float)):
|
|
row["elapsed_seconds"] = max(0, time.time() - started)
|
|
rows.append(row)
|
|
return {"subagents": rows, "delegations": []}
|
|
|
|
|
|
def transcript_tail(records, subagent_id):
|
|
result = {"subagent_id": subagent_id, "available": False, "text": "", "bytes_read": 0, "truncated": False}
|
|
record = next((r for r in records if r.get("subagent_id") == subagent_id), None)
|
|
if record is None:
|
|
return result
|
|
path = getattr(record.get("agent"), "_live_transcript_path", None)
|
|
if not isinstance(path, (str, Path)):
|
|
return result
|
|
try:
|
|
# Only the registry's own file is read; no client-supplied path is accepted.
|
|
from tools.delegation_live_log import live_transcript_root
|
|
path = Path(path)
|
|
root = live_transcript_root().resolve()
|
|
if path.is_symlink() or not path.resolve().is_relative_to(root):
|
|
return result
|
|
with path.open("rb") as stream:
|
|
size = stream.seek(0, 2)
|
|
stream.seek(max(0, size - 16384))
|
|
raw = stream.read(16384)
|
|
result.update(available=True, text=raw.decode("utf-8", errors="replace"),
|
|
bytes_read=len(raw), truncated=size > len(raw))
|
|
except OSError:
|
|
pass # A just-completed child's temporary transcript may already be gone.
|
|
return result
|