Add notification service using Google ADK
This commit is contained in:
120
src/va_agent/dynamic_instruction.py
Normal file
120
src/va_agent/dynamic_instruction.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""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 or not ctx._invocation_context:
|
||||
logger.debug("No context available for dynamic instruction")
|
||||
return ""
|
||||
|
||||
session = ctx._invocation_context.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 = [n.get("id_notificacion") for n in pending_notifications]
|
||||
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! 👋 Antes de empezar, veo que tienes {count} notificación(es) pendiente(s) en tu cuenta. ¿Te gustaría revisarlas o prefieres que te ayude con algo más?"
|
||||
"""
|
||||
|
||||
# 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,
|
||||
)
|
||||
|
||||
return instruction
|
||||
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Error building dynamic instruction for user %s", phone_number
|
||||
)
|
||||
return ""
|
||||
Reference in New Issue
Block a user