"""Dynamic instruction provider for VAia agent.""" from __future__ import annotations import logging from typing import TYPE_CHECKING if TYPE_CHECKING: from google.adk.agents.readonly_context import ReadonlyContext from va_agent.notifications import NotificationService logger = logging.getLogger(__name__) async def provide_dynamic_instruction( notification_service: NotificationService, ctx: ReadonlyContext | None = None, ) -> str: """Provide dynamic instructions based on pending notifications. This function is called by the ADK agent on each message. It: 1. Checks if this is the first message in the session (< 2 events) 2. Queries Firestore for pending notifications 3. Marks them as notified 4. 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 "" # FOR TESTING: Always check for notifications # (comment out to enable first-message-only) # Only check on first message (when events list is empty # or has only 1-2 events) # Events include both user and agent messages, so < 2 means first interaction # event_count = len(session.events) if session.events else 0 # # if event_count >= 2: # logger.debug( # "Skipping notification check: not first message (event_count=%d)", # event_count, # ) # return "" # Extract phone number from user_id (they are the same in this implementation) phone_number = session.user_id logger.info( "First message detected for user %s, checking for pending notifications", phone_number, ) try: # Fetch pending notifications pending_notifications = await notification_service.get_pending_notifications( phone_number ) if not pending_notifications: logger.info("No pending notifications for user %s", phone_number) return "" # Build dynamic instruction with notification details notification_ids = [ nid for n in pending_notifications if (nid := n.get("id_notificacion")) is not None ] count = len(pending_notifications) # Format notification details for the agent notification_details = [] for notif in pending_notifications: evento = notif.get("nombre_evento_dialogflow", "notificacion") texto = notif.get("texto", "Sin texto") notification_details.append(f" - Evento: {evento} | Texto: {texto}") details_text = "\n".join(notification_details) instruction = f""" IMPORTANTE - NOTIFICACIONES PENDIENTES: El usuario tiene {count} notificación(es) sin leer: {details_text} INSTRUCCIONES: - Menciona estas notificaciones de forma natural en tu respuesta inicial - No necesitas leerlas todas literalmente, solo hazle saber que las tiene - Sé breve y directo según tu personalidad (directo y cálido) - Si el usuario pregunta algo específico, prioriza responder eso primero\ y luego menciona las notificaciones Ejemplo: "¡Hola! 👋 Tienes {count} notificación(es)\ pendiente(s). ¿Te gustaría revisarlas?" """ # 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, ) except Exception: logger.exception( "Error building dynamic instruction for user %s", phone_number, ) return "" else: return instruction