BE-CAL-003: Add Agent model with status/heartbeat/exhausted fields
- New app/models/agent.py with Agent model, AgentStatus & ExhaustReason enums - Agent has 1-to-1 FK to User, unique agent_id (OpenClaw $AGENT_ID), claw_identifier (OpenClaw instance, convention-matches MonitoredServer.identifier) - Status fields: status (idle/on_call/busy/exhausted/offline), last_heartbeat - Exhausted tracking: exhausted_at, recovery_at, exhaust_reason (rate_limit/billing) - User model: added 'agent' back-reference (uselist=False) - Schemas: AgentResponse, AgentStatusUpdate, UserCreate now accepts agent_id+claw_identifier - UserResponse: includes agent_id when agent is bound - Users router: create_user creates Agent record when agent_id+claw_identifier provided - Auto-migration: CREATE TABLE agents in _migrate_schema() - Startup imports: agent and calendar models registered
This commit is contained in:
@@ -176,6 +176,9 @@ class UserBase(BaseModel):
|
||||
class UserCreate(UserBase):
|
||||
password: Optional[str] = None
|
||||
role_id: Optional[int] = None
|
||||
# Agent binding (both must be provided or both omitted)
|
||||
agent_id: Optional[str] = None
|
||||
claw_identifier: Optional[str] = None
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
@@ -192,6 +195,7 @@ class UserResponse(UserBase):
|
||||
is_admin: bool
|
||||
role_id: Optional[int] = None
|
||||
role_name: Optional[str] = None
|
||||
agent_id: Optional[str] = None
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
@@ -389,6 +393,47 @@ class ProposalAcceptResponse(ProposalResponse):
|
||||
from_attributes = True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Agent schemas (BE-CAL-003)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class AgentStatusEnum(str, Enum):
|
||||
IDLE = "idle"
|
||||
ON_CALL = "on_call"
|
||||
BUSY = "busy"
|
||||
EXHAUSTED = "exhausted"
|
||||
OFFLINE = "offline"
|
||||
|
||||
|
||||
class ExhaustReasonEnum(str, Enum):
|
||||
RATE_LIMIT = "rate_limit"
|
||||
BILLING = "billing"
|
||||
|
||||
|
||||
class AgentResponse(BaseModel):
|
||||
"""Read-only representation of an Agent."""
|
||||
id: int
|
||||
user_id: int
|
||||
agent_id: str
|
||||
claw_identifier: str
|
||||
status: AgentStatusEnum
|
||||
last_heartbeat: Optional[datetime] = None
|
||||
exhausted_at: Optional[datetime] = None
|
||||
recovery_at: Optional[datetime] = None
|
||||
exhaust_reason: Optional[ExhaustReasonEnum] = None
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class AgentStatusUpdate(BaseModel):
|
||||
"""Payload for updating an agent's runtime status."""
|
||||
status: AgentStatusEnum
|
||||
exhaust_reason: Optional[ExhaustReasonEnum] = None
|
||||
recovery_at: Optional[datetime] = None
|
||||
|
||||
|
||||
# Backward-compatible aliases
|
||||
ProposeStatusEnum = ProposalStatusEnum
|
||||
ProposeBase = ProposalBase
|
||||
|
||||
Reference in New Issue
Block a user