import asyncio from dataclasses import dataclass, field from datetime import datetime, timezone @dataclass(slots=True) class WisperEvent: role: str text: str timestamp: str = field( default_factory=lambda: datetime.now(timezone.utc).isoformat(timespec="seconds") ) def to_dict(self) -> dict[str, str]: return {"role": self.role, "text": self.text, "timestamp": self.timestamp} class WisperBus: def __init__(self) -> None: self._subscribers: set[asyncio.Queue[WisperEvent]] = set() self._lock = asyncio.Lock() async def subscribe(self) -> asyncio.Queue[WisperEvent]: queue: asyncio.Queue[WisperEvent] = asyncio.Queue() async with self._lock: self._subscribers.add(queue) return queue async def unsubscribe(self, queue: asyncio.Queue[WisperEvent]) -> None: async with self._lock: self._subscribers.discard(queue) async def publish(self, event: WisperEvent) -> None: async with self._lock: subscribers = list(self._subscribers) for queue in subscribers: queue.put_nowait(event)