Files
NaliiaBot/docs/AGENDA_TOOLS_EXAMPLE.py
2026-02-15 16:03:09 -05:00

485 lines
15 KiB
Python

"""
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()
"""