"""Dynamic instruction provider for VAia agent.""" from __future__ import annotations import logging import time from typing import TYPE_CHECKING if TYPE_CHECKING: from google.adk.agents.readonly_context import ReadonlyContext from va_agent.notifications import NotificationBackend logger = logging.getLogger(__name__) _SECONDS_PER_MINUTE = 60 _SECONDS_PER_HOUR = 3600 _MINUTES_PER_HOUR = 60 _HOURS_PER_DAY = 24 def _format_time_ago(now: float, ts: float) -> str: """Return a human-readable Spanish label like 'hace 3 horas'.""" diff = max(now - ts, 0) minutes = int(diff // _SECONDS_PER_MINUTE) hours = int(diff // _SECONDS_PER_HOUR) if minutes < 1: return "justo ahora" if minutes < _MINUTES_PER_HOUR: return f"hace {minutes} min" if hours < _HOURS_PER_DAY: return f"hace {hours}h" days = hours // _HOURS_PER_DAY return f"hace {days}d" async def provide_dynamic_instruction( notification_service: NotificationBackend, ctx: ReadonlyContext | None = None, ) -> str: """Provide dynamic instructions based on recent notifications. This function is called by the ADK agent on each message. It: 1. Queries Firestore for recent notifications 2. Marks them as notified 3. Returns a dynamic instruction for the agent to mention them Args: notification_service: Service for fetching/marking notifications ctx: Agent context containing session information Returns: Dynamic instruction string (empty if no notifications or not first message) """ # Only check notifications on the first message if not ctx: logger.debug("No context available for dynamic instruction") return "" session = ctx.session if not session: logger.debug("No session available for dynamic instruction") return "" # Extract phone number from user_id (they are the same in this implementation) phone_number = session.user_id logger.info( "Checking recent notifications for user %s", phone_number, ) try: # Fetch recent notifications recent_notifications = await notification_service.get_recent_notifications( phone_number ) if not recent_notifications: logger.info("No recent notifications for user %s", phone_number) return "" # Build dynamic instruction with notification details notification_ids = [n.id_notificacion for n in recent_notifications] count = len(recent_notifications) # Format notification details for the agent (most recent first) now = time.time() notification_details = [] for i, notif in enumerate(recent_notifications, 1): ago = _format_time_ago(now, notif.timestamp_creacion) notification_details.append( f" {i}. [{ago}] Evento: {notif.nombre_evento} | Texto: {notif.texto}" ) details_text = "\n".join(notification_details) header = ( f"Estas son {count} notificación(es) reciente(s)" " de las cuales el usuario podría preguntar más:" ) instruction = f""" {header} {details_text} """ # Mark notifications as notified in Firestore await notification_service.mark_as_notified(phone_number, notification_ids) logger.info( "Returning dynamic instruction with %d notification(s) for user %s", count, phone_number, ) logger.debug("Dynamic instruction content:\n%s", instruction) except Exception: logger.exception( "Error building dynamic instruction for user %s", phone_number, ) return "" else: return instruction