"""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