485 lines
15 KiB
Python
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()
|
|
"""
|