"""Per-capture evidence model. UIState represents a deduplicated semantic state. UIObservation represents one concrete capture and is therefore never deduplicated. """ from __future__ import annotations import uuid from dataclasses import dataclass, field from datetime import datetime from typing import Any, Optional SCHEMA_OBSERVATION = "openclaw.ui_inspector.observation.v1" def _now_iso() -> str: return datetime.now().astimezone().isoformat() def _new_id() -> str: return f"obs_{uuid.uuid4().hex[:12]}" @dataclass class UIObservation: schema: str = SCHEMA_OBSERVATION id: str = field(default_factory=_new_id) captured_at: str = field(default_factory=_now_iso) state_id: str = "" previous_observation_id: Optional[str] = None change_reason: str = "capture" surface: str = "windows" driver: str = "" page_id: str = "" document_id: str = "" frame_id: str = "" url: str = "" page_title: str = "" tree_path: str = "" index_path: str = "" locatable_path: str = "" screenshot_path: str = "" stats: dict[str, Any] = field(default_factory=dict) selection: dict[str, Any] = field(default_factory=dict) may_contain_sensitive_data: bool = False