"""Shared, thread/async-safe screen context. The perception loop keeps writing the latest ScreenObservation here; the conversation loop reads it when the user says something. We only keep the most recent observation plus a short ring buffer of recent ones so the Brain can notice "the screen changed" without us re-sending every frame. """ from __future__ import annotations import asyncio from collections import deque from .interfaces import ScreenObservation class SharedScreenContext: def __init__(self, history: int = 8) -> None: self._latest: ScreenObservation | None = None self._recent: deque[ScreenObservation] = deque(maxlen=history) self._lock = asyncio.Lock() async def update(self, obs: ScreenObservation) -> None: async with self._lock: self._latest = obs self._recent.append(obs) async def latest(self) -> ScreenObservation | None: async with self._lock: return self._latest async def recent(self) -> list[ScreenObservation]: async with self._lock: return list(self._recent)