- matrix-gateway: POST /internal/matrix/presence/online endpoint - usePresenceHeartbeat hook with activity tracking - Auto away after 5 min inactivity - Offline on page close/visibility change - Integrated in MatrixChatRoom component
248 lines
7.1 KiB
Python
248 lines
7.1 KiB
Python
"""
|
|
Living Map Service Models
|
|
Phase 9: Full Stack Living Map
|
|
"""
|
|
from pydantic import BaseModel, Field
|
|
from typing import Optional, List, Dict, Any, Literal
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
|
|
# ============================================================================
|
|
# Layer Types
|
|
# ============================================================================
|
|
|
|
LayerType = Literal["city", "space", "nodes", "agents"]
|
|
EntityType = Literal["city", "space", "node", "agent", "dao", "microdao", "channel"]
|
|
EntityStatus = Literal["active", "inactive", "online", "offline", "warning", "error", "idle"]
|
|
|
|
# ============================================================================
|
|
# City Layer Models
|
|
# ============================================================================
|
|
|
|
class CityItem(BaseModel):
|
|
"""MicroDAO in City layer"""
|
|
id: str
|
|
slug: str
|
|
name: str
|
|
status: EntityStatus
|
|
agents: int = 0
|
|
nodes: int = 0
|
|
members: int = 0
|
|
description: Optional[str] = None
|
|
|
|
class CityLayer(BaseModel):
|
|
"""City layer data"""
|
|
microdaos_total: int = 0
|
|
active_users: int = 0
|
|
active_agents: int = 0
|
|
health: str = "green"
|
|
items: List[CityItem] = []
|
|
|
|
# ============================================================================
|
|
# Space Layer Models
|
|
# ============================================================================
|
|
|
|
class PlanetItem(BaseModel):
|
|
"""DAO planet in Space layer"""
|
|
id: str
|
|
name: str
|
|
type: str = "dao"
|
|
status: EntityStatus
|
|
orbits: List[str] = [] # node IDs
|
|
treasury_value: Optional[Decimal] = None
|
|
active_proposals: int = 0
|
|
|
|
class NodeInSpace(BaseModel):
|
|
"""Node in Space layer (orbital view)"""
|
|
id: str
|
|
name: str
|
|
status: EntityStatus
|
|
cpu: float = 0.0
|
|
gpu: float = 0.0
|
|
memory: float = 0.0
|
|
alerts: List[str] = []
|
|
|
|
class SpaceLayer(BaseModel):
|
|
"""Space layer data"""
|
|
planets: List[PlanetItem] = []
|
|
nodes: List[NodeInSpace] = []
|
|
|
|
# ============================================================================
|
|
# Nodes Layer Models
|
|
# ============================================================================
|
|
|
|
class NodeMetrics(BaseModel):
|
|
"""Node hardware metrics"""
|
|
cpu: float = 0.0
|
|
gpu: float = 0.0
|
|
ram: float = 0.0
|
|
disk: float = 0.0
|
|
net_in: int = 0
|
|
net_out: int = 0
|
|
temperature: Optional[float] = None
|
|
|
|
class NodeItem(BaseModel):
|
|
"""Node in Nodes layer"""
|
|
id: str
|
|
name: str
|
|
microdao_id: Optional[str] = None
|
|
status: EntityStatus
|
|
metrics: NodeMetrics
|
|
alerts: List[str] = []
|
|
uptime_seconds: Optional[int] = None
|
|
last_seen: Optional[datetime] = None
|
|
|
|
class NodesLayer(BaseModel):
|
|
"""Nodes layer data"""
|
|
items: List[NodeItem] = []
|
|
total_cpu: float = 0.0
|
|
total_gpu: float = 0.0
|
|
total_ram: float = 0.0
|
|
|
|
# ============================================================================
|
|
# Agents Layer Models
|
|
# ============================================================================
|
|
|
|
class AgentUsage(BaseModel):
|
|
"""Agent usage statistics"""
|
|
llm_calls_24h: int = 0
|
|
tokens_24h: int = 0
|
|
messages_24h: int = 0
|
|
avg_response_time_ms: Optional[float] = None
|
|
|
|
class AgentItem(BaseModel):
|
|
"""Agent in Agents layer"""
|
|
id: str
|
|
name: str
|
|
kind: str
|
|
microdao_id: Optional[str] = None
|
|
status: EntityStatus
|
|
usage: AgentUsage
|
|
model: Optional[str] = None
|
|
last_active: Optional[datetime] = None
|
|
|
|
class AgentsLayer(BaseModel):
|
|
"""Agents layer data"""
|
|
items: List[AgentItem] = []
|
|
total_agents: int = 0
|
|
online_agents: int = 0
|
|
total_llm_calls_24h: int = 0
|
|
|
|
# ============================================================================
|
|
# Snapshot Models
|
|
# ============================================================================
|
|
|
|
class SnapshotMeta(BaseModel):
|
|
"""Metadata for snapshot"""
|
|
source_services: List[str] = []
|
|
generated_at: datetime
|
|
version: str = "1.0"
|
|
request_id: Optional[str] = None
|
|
|
|
class LivingMapSnapshot(BaseModel):
|
|
"""Complete Living Map state"""
|
|
generated_at: datetime
|
|
layers: Dict[str, Any] # Flexible for different layer structures
|
|
meta: SnapshotMeta
|
|
|
|
class LivingMapSnapshotTyped(BaseModel):
|
|
"""Typed version of Living Map snapshot"""
|
|
generated_at: datetime
|
|
layers: Dict[str, Any] = Field(default_factory=dict)
|
|
meta: SnapshotMeta
|
|
|
|
class Config:
|
|
arbitrary_types_allowed = True
|
|
|
|
# ============================================================================
|
|
# Entity Models
|
|
# ============================================================================
|
|
|
|
class EntitySummary(BaseModel):
|
|
"""Minimal entity info for lists"""
|
|
id: str
|
|
type: EntityType
|
|
label: str
|
|
status: EntityStatus
|
|
layer: LayerType
|
|
|
|
class EntityDetail(BaseModel):
|
|
"""Detailed entity information"""
|
|
id: str
|
|
type: EntityType
|
|
layer: LayerType
|
|
data: Dict[str, Any]
|
|
|
|
# ============================================================================
|
|
# History / Event Models
|
|
# ============================================================================
|
|
|
|
class HistoryItem(BaseModel):
|
|
"""Single history event"""
|
|
id: str
|
|
timestamp: datetime
|
|
event_type: str
|
|
payload: Dict[str, Any]
|
|
source_service: Optional[str] = None
|
|
entity_id: Optional[str] = None
|
|
entity_type: Optional[str] = None
|
|
|
|
class HistoryResponse(BaseModel):
|
|
"""History query response"""
|
|
items: List[HistoryItem]
|
|
total: int
|
|
has_more: bool = False
|
|
|
|
# ============================================================================
|
|
# WebSocket Models
|
|
# ============================================================================
|
|
|
|
class WSMessageType(BaseModel):
|
|
"""WebSocket message type"""
|
|
kind: Literal["snapshot", "event", "ping", "error"]
|
|
|
|
class WSSnapshotMessage(BaseModel):
|
|
"""WebSocket snapshot message"""
|
|
kind: Literal["snapshot"] = "snapshot"
|
|
data: LivingMapSnapshot
|
|
|
|
class WSEventMessage(BaseModel):
|
|
"""WebSocket event message"""
|
|
kind: Literal["event"] = "event"
|
|
event_type: str
|
|
timestamp: datetime
|
|
payload: Dict[str, Any]
|
|
|
|
class WSPingMessage(BaseModel):
|
|
"""WebSocket ping message"""
|
|
kind: Literal["ping"] = "ping"
|
|
timestamp: datetime
|
|
|
|
class WSErrorMessage(BaseModel):
|
|
"""WebSocket error message"""
|
|
kind: Literal["error"] = "error"
|
|
error: str
|
|
timestamp: datetime
|
|
|
|
# ============================================================================
|
|
# Query Parameters
|
|
# ============================================================================
|
|
|
|
class HistoryQueryParams(BaseModel):
|
|
"""Query parameters for history endpoint"""
|
|
since: Optional[datetime] = None
|
|
until: Optional[datetime] = None
|
|
event_type: Optional[str] = None
|
|
entity_id: Optional[str] = None
|
|
limit: int = Field(default=200, ge=1, le=1000)
|
|
offset: int = Field(default=0, ge=0)
|
|
|
|
class EntitiesQueryParams(BaseModel):
|
|
"""Query parameters for entities endpoint"""
|
|
type: Optional[EntityType] = None
|
|
layer: Optional[LayerType] = None
|
|
status: Optional[EntityStatus] = None
|
|
limit: int = Field(default=100, ge=1, le=500)
|
|
offset: int = Field(default=0, ge=0)
|
|
|