"""Agent message schemas. The base shapes come from hub-core. STATE-WP-0093 extends them locally with broadcast kinds, expiry, supersede and per-reader receipt fields; direct messages keep the hub-core semantics (the new fields stay at their defaults). """ import uuid from datetime import datetime from hub_core.schemas.agent_message import MessageCreate as _HubMessageCreate from hub_core.schemas.agent_message import MessageRead as _HubMessageRead from hub_core.schemas.agent_message import MessageReply from pydantic import BaseModel class MessageCreate(_HubMessageCreate): # Only meaningful for broadcasts: news | standing. A broadcast without a # kind defaults to ``news``; direct messages must leave it unset or # ``message``. kind: str | None = None expires_at: datetime | None = None supersedes_id: uuid.UUID | None = None class MessageRead(_HubMessageRead): kind: str = "message" expires_at: datetime | None = None supersedes_id: uuid.UUID | None = None # Per-reader receipt state; populated for broadcasts when the request is # scoped to a reader (``to_agent`` on list, ``reader`` on mark-read/ack). # For such responses ``read_at`` is the reader's own read time. reader: str | None = None delivered_at: datetime | None = None acknowledged_at: datetime | None = None class MessageMarkRead(BaseModel): reader: str | None = None ack: bool = False class MessageAck(BaseModel): agent: str class NoticeStatus(BaseModel): id: uuid.UUID from_agent: str subject: str body: str created_at: datetime expires_at: datetime | None = None supersedes_id: uuid.UUID | None = None acknowledged: list[str] = [] delivered_only: list[str] = [] unreached: list[str] = [] acked_count: int = 0 delivered_only_count: int = 0 unreached_count: int = 0 class StandingNoticeDigest(BaseModel): id: uuid.UUID subject: str expires_at: datetime | None = None acked: int = 0 pending: int = 0 __all__ = [ "MessageAck", "MessageCreate", "MessageMarkRead", "MessageRead", "MessageReply", "NoticeStatus", "StandingNoticeDigest", ]