from __future__ import annotations from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from yuxi.channels.models import DeliveryResult from .adapter import WeChatAdapter class WeChatHeartbeatAdapter: def __init__(self, config: dict[str, Any]): self._typing_enabled = config.get("typing_indicator", False) self._heartbeat_interval = config.get("heartbeat_interval", 300.0) @property def typing_enabled(self) -> bool: return self._typing_enabled async def send_typing_indicator(self, send_fn, chat_id: str, active: bool = True) -> None: if not self._typing_enabled or not active: return try: await send_fn(chat_id, "...") except Exception: pass async def send_typing_via_response( self, send_fn, chat_id: str, active: bool = True, ) -> DeliveryResult | None: if not self._typing_enabled or not active: return None try: from yuxi.channels.models import ( ChannelIdentity, ChannelResponse, ChannelType, ) identity = ChannelIdentity( channel_id="wechat", channel_type=ChannelType.WECHAT, channel_user_id="", channel_chat_id=chat_id, ) response = ChannelResponse(identity=identity, content="...") return await send_fn(response) except Exception: return None async def heartbeat_check(self, adapter: WeChatAdapter) -> dict[str, Any]: import time start = time.monotonic() try: health = await adapter.health_check() latency = (time.monotonic() - start) * 1000 return {"alive": health.status == "healthy", "latencyMs": latency} except Exception as e: return {"alive": False, "lastError": str(e)} @staticmethod def should_preserve_thread_id_for_group_heartbeat(config: dict[str, Any]) -> bool: return config.get("preserve_heartbeat_thread_id_for_group", False)