ai-memory-backend / api /admin_state.py
Baida07's picture
sync: 172 file da Baida98/AI@789d6ce1 (2026-08-22 17:41 UTC) [deploy-all] (#17)
5176170
Raw
History Blame
3.33 kB
"""Stato operativo amministrativo protetto da JWT Supabase admin."""
from __future__ import annotations
from datetime import datetime, timedelta, timezone
from typing import Any
from fastapi import APIRouter, Depends, Query
from .auth_guard import require_admin_user
from .private_state import _MAX_TASK_PAGE, _as_epoch_ms, _call, _json_object
router = APIRouter(
prefix="/api/admin/state",
tags=["admin"],
dependencies=[Depends(require_admin_user)],
)
@router.get("/sessions")
async def admin_sessions(
max_age_ms: int = Query(default=300_000, ge=10_000, le=3_600_000),
limit: int = Query(default=100, ge=1, le=200),
) -> dict[str, object]:
cutoff = (datetime.now(timezone.utc) - timedelta(milliseconds=max_age_ms)).isoformat()
def operation(client: Any):
return client.table("agent_tasks").select("task_id,context,updated_at").eq("status", "__session__").gte("updated_at", cutoff).order("updated_at", desc=True).limit(limit).execute()
result = await _call(operation)
sessions = []
for row in result.data or []:
context = _json_object(row.get("context"))
session_id = str(context.get("sessionId") or row.get("task_id") or "").strip()
if not session_id:
continue
claimed = context.get("claimedFiles")
sessions.append({
"session_id": session_id,
"session_name": str(context.get("sessionName") or session_id)[:160],
"sprint": str(context["sprint"])[:120] if context.get("sprint") else None,
"claimed_files": [str(item)[:300] for item in claimed[:100]] if isinstance(claimed, list) else [],
"last_heartbeat": _as_epoch_ms(context.get("lastHeartbeat")) or _as_epoch_ms(row.get("updated_at")),
"current_task": str(context["currentTask"])[:500] if context.get("currentTask") else None,
})
return {"sessions": sessions}
@router.get("/tasks")
async def admin_tasks(
limit: int = Query(default=20, ge=1, le=_MAX_TASK_PAGE),
offset: int = Query(default=0, ge=0, le=10_000),
status: str | None = Query(default=None, max_length=64),
) -> dict[str, object]:
normalized_status = status.strip().upper() if status else ""
def operation(client: Any):
query = client.table("agent_tasks").select("task_id,goal,status,updated_at").neq("status", "__session__").neq("status", "__config__")
if normalized_status:
query = query.eq("status", normalized_status)
page = query.order("updated_at", desc=True).range(offset, offset + limit - 1).execute()
all_statuses = client.table("agent_tasks").select("status").neq("status", "__session__").neq("status", "__config__").limit(2_000).execute()
return page, all_statuses
page, all_statuses = await _call(operation)
counts: dict[str, int] = {}
for row in all_statuses.data or []:
key = str(row.get("status") or "UNKNOWN").upper()
counts[key] = counts.get(key, 0) + 1
tasks = [{
"task_id": str(row.get("task_id") or ""),
"goal": str(row.get("goal") or "")[:1_000],
"status": str(row.get("status") or "UNKNOWN"),
"updated_at": _as_epoch_ms(row.get("updated_at")),
} for row in page.data or []]
return {"tasks": tasks, "counts": counts, "offset": offset, "limit": limit}