import logging from yuxi.channel.extensions.intercom.client import IntercomClient logger = logging.getLogger(__name__) class HandoffDetector: @staticmethod async def is_human_takeover(client: IntercomClient, conversation_id: str, bot_admin_id: str) -> bool: try: conv = await client.get_conversation(conversation_id) except Exception: logger.warning("Failed to fetch conversation %s for handoff check", conversation_id, exc_info=True) return False assignee = conv.get("assignee") or {} if assignee and assignee.get("type") == "admin": admin_id = str(assignee.get("id", "")) if admin_id and admin_id != bot_admin_id: return True return False @staticmethod async def check_recent_admin_reply(client: IntercomClient, conversation_id: str, bot_admin_id: str) -> bool: try: parts = await client.get_conversation_parts(conversation_id) except Exception: logger.warning("Failed to fetch conversation parts for handoff check", exc_info=True) return False for part in reversed(parts): author = part.get("author", {}) if author.get("type") == "admin" and str(author.get("id", "")) != bot_admin_id: return True if part.get("part_type") == "comment" and author.get("type") in ("contact", "user"): break return False @staticmethod async def get_last_admin_reply_time(client: IntercomClient | None, conversation_id: str, bot_admin_id: str) -> float | None: if client is None: return None try: parts = await client.get_conversation_parts(conversation_id) except Exception: return None for part in reversed(parts): author = part.get("author", {}) if author.get("type") == "admin" and str(author.get("id", "")) != bot_admin_id: created_at = part.get("created_at", 0) return float(created_at) if created_at else None return None