""" Ejemplo práctico: Herramientas para gestión de agenda. Este archivo muestra cómo implementar tools reales para el agente Naliia que está enfocado en gestión de agenda. NOTA: Este es un archivo de ejemplo para entender la estructura. Para usar estas herramientas reales, cópilas al archivo: src/naliiabot/bot/tools/tools.py """ from typing import Any, Dict from src.naliiabot.bot.tools.tool_registry import BaseTool class ObtenerAgendaTool(BaseTool): """ Obtiene los eventos de la agenda del usuario para una fecha. Ejemplo de uso por el LLM: - "¿Qué tengo programado para el 15 de febrero?" - "Muéstrame mi agenda de hoy" """ @property def name(self) -> str: return "obtener_agenda" @property def description(self) -> str: return ( "Obtiene los eventos programados en la agenda del usuario " "para una fecha específica. Retorna una lista con hora, título " "y descripción de cada evento." ) @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "fecha": { "type": "string", "description": "Fecha en formato YYYY-MM-DD (ej: 2026-02-15)", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }, "usuario_id": { "type": "string", "description": "ID único del usuario" } }, "required": ["fecha", "usuario_id"] } def invoke(self, **kwargs) -> str: """ Ejecuta la obtención de eventos. Args: fecha: Fecha a consultar (YYYY-MM-DD) usuario_id: ID del usuario Returns: String con los eventos o mensaje de error """ fecha = kwargs.get("fecha", "") usuario_id = kwargs.get("usuario_id", "") if not fecha or not usuario_id: return "Error: Se requieren 'fecha' y 'usuario_id'" try: # Aquí iría la consulta real a base de datos # eventos = db.obtener_eventos(usuario_id, fecha) # Simulación para el ejemplo eventos_simulados = { "2026-02-15": [ {"hora": "09:00", "titulo": "Standup", "duracion": 30}, {"hora": "10:30", "titulo": "Reunión con equipo", "duracion": 60}, {"hora": "14:00", "titulo": "Review", "duracion": 45}, ] } eventos = eventos_simulados.get(fecha, []) if not eventos: return f"No hay eventos programados para {fecha}" resultado = f"Agenda para {fecha}:\n" for evento in eventos: resultado += f" • {evento['hora']}: {evento['titulo']} ({evento['duracion']} min)\n" return resultado except Exception as e: return f"Error al obtener agenda: {str(e)}" class AgregarEventoTool(BaseTool): """ Agrega un nuevo evento a la agenda del usuario. Ejemplo de uso: - "Agrega una reunión el 15 de febrero a las 10:00" - "Programa una llamada el 20/02 a las 14:30 por 45 minutos" """ @property def name(self) -> str: return "agregar_evento" @property def description(self) -> str: return ( "Agrega un nuevo evento a la agenda del usuario. " "Requiere título, fecha, hora de inicio y duración." ) @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "usuario_id": { "type": "string", "description": "ID del usuario propietario de la agenda" }, "titulo": { "type": "string", "description": "Título o nombre del evento" }, "fecha": { "type": "string", "description": "Fecha en formato YYYY-MM-DD", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }, "hora_inicio": { "type": "string", "description": "Hora de inicio en formato HH:MM (24h)", "pattern": "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$" }, "duracion_minutos": { "type": "integer", "description": "Duración del evento en minutos", "default": 30, "minimum": 5, "maximum": 480 }, "descripcion": { "type": "string", "description": "Descripción adicional del evento (opcional)" }, "participantes": { "type": "array", "items": {"type": "string"}, "description": "Lista de emails de participantes (opcional)" } }, "required": ["usuario_id", "titulo", "fecha", "hora_inicio"] } def invoke(self, **kwargs) -> str: """ Agrega un evento a la agenda. Returns: Confirmación del evento agregado o mensaje de error """ usuario_id = kwargs.get("usuario_id") titulo = kwargs.get("titulo") fecha = kwargs.get("fecha") hora = kwargs.get("hora_inicio") duracion = kwargs.get("duracion_minutos", 30) descripcion = kwargs.get("descripcion", "") participantes = kwargs.get("participantes", []) # Validaciones if not all([usuario_id, titulo, fecha, hora]): return "Error: Faltan parámetros requeridos" try: # Aquí iría la lógica para guardar en BD # db.agregar_evento(usuario_id, titulo, fecha, hora, duracion, etc) resultado = ( f"✓ Evento agregado correctamente\n" f" Título: {titulo}\n" f" Fecha: {fecha}\n" f" Hora: {hora}\n" f" Duración: {duracion} minutos" ) if descripcion: resultado += f"\n Descripción: {descripcion}" if participantes: resultado += f"\n Participantes: {', '.join(participantes)}" return resultado except Exception as e: return f"Error al agregar evento: {str(e)}" class ModificarEventoTool(BaseTool): """ Modifica los detalles de un evento existente. Ejemplo de uso: - "Cambia la reunión de las 10:00 a las 11:00" - "Aumenta la duración de la reunión a 60 minutos" """ @property def name(self) -> str: return "modificar_evento" @property def description(self) -> str: return ( "Modifica los detalles de un evento existente en la agenda. " "Se puede cambiar hora, duración, título o descripción." ) @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "evento_id": { "type": "string", "description": "ID único del evento a modificar" }, "usuario_id": { "type": "string", "description": "ID del usuario propietario" }, "titulo": { "type": "string", "description": "Nuevo título (opcional)" }, "hora_inicio": { "type": "string", "description": "Nueva hora en formato HH:MM (opcional)" }, "duracion_minutos": { "type": "integer", "description": "Nueva duración en minutos (opcional)" }, "descripcion": { "type": "string", "description": "Nueva descripción (opcional)" } }, "required": ["evento_id", "usuario_id"] } def invoke(self, **kwargs) -> str: evento_id = kwargs.get("evento_id") usuario_id = kwargs.get("usuario_id") cambios = {} if "titulo" in kwargs: cambios["titulo"] = kwargs["titulo"] if "hora_inicio" in kwargs: cambios["hora_inicio"] = kwargs["hora_inicio"] if "duracion_minutos" in kwargs: cambios["duracion_minutos"] = kwargs["duracion_minutos"] if "descripcion" in kwargs: cambios["descripcion"] = kwargs["descripcion"] if not cambios: return "Error: No hay cambios para aplicar" try: # db.modificar_evento(usuario_id, evento_id, cambios) resultado = f"✓ Evento {evento_id} modificado:\n" for campo, valor in cambios.items(): resultado += f" • {campo}: {valor}\n" return resultado except Exception as e: return f"Error al modificar evento: {str(e)}" class EliminarEventoTool(BaseTool): """ Elimina un evento de la agenda. Ejemplo de uso: - "Elimina la reunión de las 10:00" - "Cancela el evento 'Standup' del 15 de febrero" """ @property def name(self) -> str: return "eliminar_evento" @property def description(self) -> str: return ( "Elimina un evento de la agenda del usuario. " "Requiere confirmación para evitar eliminaciones accidentales." ) @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "evento_id": { "type": "string", "description": "ID único del evento a eliminar" }, "usuario_id": { "type": "string", "description": "ID del usuario propietario" }, "confirmar": { "type": "boolean", "description": "Confirmación de eliminación", "default": False } }, "required": ["evento_id", "usuario_id", "confirmar"] } def invoke(self, **kwargs) -> str: evento_id = kwargs.get("evento_id") usuario_id = kwargs.get("usuario_id") confirmar = kwargs.get("confirmar", False) if not confirmar: return ( f"⚠️ Confirmación requerida para eliminar evento {evento_id}. " f"Por favor, confirma: confirmar=true" ) try: # db.eliminar_evento(usuario_id, evento_id) return f"✓ Evento {evento_id} eliminado correctamente de la agenda" except Exception as e: return f"Error al eliminar evento: {str(e)}" class ListarAgendaTool(BaseTool): """ Lista todos los eventos del usuario en un rango de fechas. Ejemplo de uso: - "Muestra mi agenda de la próxima semana" - "¿Qué tengo programado entre el 10 y el 20 de febrero?" """ @property def name(self) -> str: return "listar_agenda" @property def description(self) -> str: return ( "Lista todos los eventos de la agenda del usuario " "dentro de un rango de fechas especificado." ) @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "usuario_id": { "type": "string", "description": "ID del usuario" }, "fecha_inicio": { "type": "string", "description": "Fecha de inicio en formato YYYY-MM-DD" }, "fecha_fin": { "type": "string", "description": "Fecha de fin en formato YYYY-MM-DD" }, "filtro_titulo": { "type": "string", "description": "Filtrar por título del evento (opcional)" } }, "required": ["usuario_id", "fecha_inicio", "fecha_fin"] } def invoke(self, **kwargs) -> str: usuario_id = kwargs.get("usuario_id") fecha_inicio = kwargs.get("fecha_inicio") fecha_fin = kwargs.get("fecha_fin") filtro = kwargs.get("filtro_titulo", "") try: # eventos = db.listar_eventos(usuario_id, fecha_inicio, fecha_fin, filtro) resultado = ( f"Agenda de {fecha_inicio} a {fecha_fin}:\n" f" • Total de eventos: 3\n" f" • Horas ocupadas: 9\n" f" • Tiempo libre: 7 horas" ) return resultado except Exception as e: return f"Error al listar agenda: {str(e)}" # ============================================================================ # CÓMO USAR ESTAS HERRAMIENTAS # ============================================================================ """ OPCIÓN 1: Copiar a tools.py 1. Copia las clases de herramientas a: src/naliiabot/bot/tools/tools.py 2. En tu código principal: from src.naliiabot.bot.tools import ToolRegistry from src.naliiabot.bot.tools.tools import ( ObtenerAgendaTool, AgregarEventoTool, ModificarEventoTool, EliminarEventoTool, ListarAgendaTool ) from src.naliiabot.bot.agent.agent import Agent from langchain_anthropic import ChatAnthropic # Configurar modelo = ChatAnthropic(model="claude-3-5-sonnet-20241022") registry = ToolRegistry() # Registrar herramientas registry.register(ObtenerAgendaTool()) registry.register(AgregarEventoTool()) registry.register(ModificarEventoTool()) registry.register(EliminarEventoTool()) registry.register(ListarAgendaTool()) # Crear agente agent = Agent( model=modelo, tools=registry.get_all_tools_as_langchain() ) OPCIÓN 2: Usar factory pattern Crea src/naliiabot/bot/tools/factory.py: from .tool_registry import ToolRegistry from .tools import ( ObtenerAgendaTool, AgregarEventoTool, ModificarEventoTool, EliminarEventoTool, ListarAgendaTool ) def crear_registry_agenda() -> ToolRegistry: registry = ToolRegistry() registry.register(ObtenerAgendaTool()) registry.register(AgregarEventoTool()) registry.register(ModificarEventoTool()) registry.register(EliminarEventoTool()) registry.register(ListarAgendaTool()) return registry Luego úsalo: from src.naliiabot.bot.tools.factory import crear_registry_agenda registry = crear_registry_agenda() tools = registry.get_all_tools_as_langchain() """