Skip to main content

hackagent.interfaces.web._serializers

Render LocalBackend records in the HackAgent REST wire format.

The bundled web UI is the same single-page app that runs against api.hackagent.dev; its generated client expects Django REST Framework payloads (snake_case keys, {count, next, previous, results} pages). These functions are the offline-mode adapter: they translate the SQLite-backed records of hackagent.storage.records into exactly those shapes so the SPA cannot tell the difference.

Fields the local store has no equivalent for (per-request HTTP metadata, credits, Auth0 identifiers) are emitted as None/zero rather than omitted — the generated client dereferences them unconditionally.

LOCAL_USER_ID​

Identity presented by offline mode. The local store has a single implicit user; the SPA still needs a stable id/username pair to render headers.

paginate​

def paginate(items: List[Dict[str, Any]], total: int, page: int,
page_size: int) -> Dict[str, Any]

Wrap items in DRF's PageNumberPagination envelope.

next/previous are booleans-as-URLs in DRF; the SPA only checks them for truthiness to decide whether to request another page, so a sentinel string is enough and avoids having to reconstruct absolute URLs.

organization​

def organization(org_id: UUID) -> Dict[str, Any]

Full Organization payload. Credits are meaningless offline: report 0.

result​

def result(record: Any, traces: Optional[List[Any]] = None) -> Dict[str, Any]

Serialise a result.

traces is always present in the wire format (the generated client maps over it unconditionally); pass None for list endpoints, where loading every trace would turn one page into hundreds of queries.

run_summary​

def run_summary(record: Any,
results: List[Any],
agent_name: Optional[str] = None,
attack_type: Optional[str] = None,
org_id: Optional[UUID] = None) -> Dict[str, Any]

Serialise a run with the per-outcome counts the run list renders.