"""Pydantic schemas for OpenClaw Gateway RPC response parsing. These schemas map the raw JSON responses from gateway RPC methods to typed Python objects. They are used by GatewayCollectorService to parse responses before storing data in Mission Control's monitoring models. Note: These are NOT DB models (those are in app/models/monitoring.py). These are purely for RPC response parsing. """ from __future__ import annotations from datetime import datetime from typing import Any from pydantic import BaseModel, Field class CostPeriod(BaseModel): """Cost period breakdown.""" start: datetime end: datetime total: float = Field(default=0.0) model_costs: dict[str, float] | None = Field(default=None, alias="models") provider_costs: dict[str, float] | None = Field(default=None) token_counts: dict[str, int] | None = Field(default=None) class CostResponse(BaseModel): """Response from usage.cost RPC method.""" period_start: datetime = Field(alias="period_start") period_end: datetime = Field(alias="period_end") total_cost: float = Field(alias="total", default=0.0) model_costs: dict[str, float] | None = Field(alias="models", default=None) provider_costs: dict[str, float] | None = Field(default=None) token_counts: dict[str, int] | None = Field(alias="tokens", default=None) class UsageStatusResponse(BaseModel): """Response from usage.status RPC method.""" tokens_used: int = Field(default=0) tokens_limit: int | None = Field(default=None) cost_used: float = Field(default=0.0) cost_limit: float | None = Field(default=None) model_usage: dict[str, dict[str, Any]] | None = Field(default=None) class CronJobStatus(BaseModel): """Individual cron job status.""" job_name: str = Field(alias="name") schedule: str enabled: bool = Field(default=True) last_run_at: datetime | None = Field(default=None, alias="lastRun") next_run_at: datetime | None = Field(default=None, alias="nextRun") status: str = Field(default="idle") failure_count: int = Field(default=0, alias="failureCount") last_error: str | None = Field(default=None, alias="lastError") metadata_: dict[str, Any] | None = Field(default=None, alias="metadata") model_config = {"populate_by_name": True} class CronJobStatusResponse(BaseModel): """Response from cron.list RPC method.""" jobs: list[CronJobStatus] = Field(default_factory=list) class SessionPreview(BaseModel): """Session preview data.""" session_key: str = Field(alias="key") event_type: str = Field(default="unknown", alias="eventType") model: str | None = Field(default=None) agent_id: str | None = Field(default=None, alias="agentId") channel: str | None = Field(default=None) context_percent: float | None = Field(default=None, alias="contextPct") token_counts: dict[str, int] | None = Field(default=None) cost: float | None = Field(default=None) metadata_: dict[str, Any] | None = Field(default=None, alias="metadata") model_config = {"populate_by_name": True} class SessionsListResponse(BaseModel): """Response from sessions.list RPC method.""" sessions: list[SessionPreview] = Field(default_factory=list) class SessionPreviewResponse(BaseModel): """Response from sessions.preview RPC method.""" session_key: str = Field(alias="key") event_type: str = Field(default="preview", alias="eventType") model: str | None = Field(default=None) agent_id: str | None = Field(default=None, alias="agentId") channel: str | None = Field(default=None) context_percent: float | None = Field(default=None, alias="contextPct") token_counts: dict[str, int] | None = Field(default=None) cost: float | None = Field(default=None) metadata_: dict[str, Any] | None = Field(default=None, alias="metadata") model_config = {"populate_by_name": True} class GatewayHealthMetrics(BaseModel): """System health metrics from gateway health response.""" cpu_percent: float | None = Field(default=None, alias="cpu") cpu_cores: int | None = Field(default=None, alias="cpuCores") ram_used_bytes: int | None = Field(default=None, alias="ramUsed") ram_total_bytes: int | None = Field(default=None, alias="ramTotal") ram_percent: float | None = Field(default=None, alias="ramPercent") swap_used_bytes: int | None = Field(default=None, alias="swapUsed") swap_total_bytes: int | None = Field(default=None, alias="swapTotal") swap_percent: float | None = Field(default=None, alias="swapPercent") disk_path: str = Field(default="/", alias="diskPath") disk_used_bytes: int | None = Field(default=None, alias="diskUsed") disk_total_bytes: int | None = Field(default=None, alias="diskTotal") disk_percent: float | None = Field(default=None, alias="diskPercent") metadata_: dict[str, Any] | None = Field(default=None, alias="metadata") model_config = {"populate_by_name": True} class GatewayHealthResponse(BaseModel): """Response from health RPC method.""" status: str = Field(default="unknown") pid: int | None = Field(default=None) uptime_ms: int | None = Field(default=None, alias="uptimeMs") memory_bytes: int | None = Field(default=None, alias="memory") rss_bytes: int | None = Field(default=None, alias="rss") timestamp: datetime | None = Field(default=None) metrics: GatewayHealthMetrics | None = Field(default=None) class GatewayStatus(BaseModel): """Gateway runtime status.""" gateway_live: bool = Field(default=False, alias="live") gateway_ready: bool = Field(default=False, alias="ready") gateway_uptime_ms: int = Field(default=0, alias="uptimeMs") gateway_pid: int = Field(default=0, alias="pid") gateway_version: str = Field(default="unknown", alias="version") agents_count: int = Field(default=0, alias="agents") class GatewayStatusResponse(BaseModel): """Response from status RPC method.""" status: str = Field(default="unknown") gateway: GatewayStatus class SubAgentRun(BaseModel): """Sub-agent execution record.""" parent_session_key: str = Field(alias="parentSessionKey") session_event_id: str | None = Field(default=None, alias="sessionId") agent: str | None = Field(default=None) model: str | None = Field(default=None) status: str = Field(default="pending") duration_ms: int | None = Field(default=None, alias="durationMs") cost: float | None = Field(default=None) token_counts: dict[str, int] | None = Field(default=None) metadata_: dict[str, Any] | None = Field(default=None, alias="metadata") model_config = {"populate_by_name": True}