Tema
Seguridad y límites
Como el canal de agentes es público, ur trae dos capas de defensa entre el mensaje del usuario y el modelo: límites de abuso (cuánto se puede hablar) y filtros de contenido (qué se puede decir).
Las dos se configuran en el panel. Lo importante para tu integración es cómo se manifiestan en la respuesta, porque no se parecen a un error de API.
El orden en que se aplica todo
Cada mensaje pasa por estas puertas, en este orden:
- ¿El agente está activo? — el interruptor general del agente.
- Longitud — se recorta a
maxMessageLength. - Límite de ráfaga — mensajes demasiado seguidos.
- Límite por hora — cuántos mensajes por cliente y hora.
- Filtros de contenido — las cinco comprobaciones de abajo.
Si alguna bloquea, el turno no llega al modelo y se responde con un mensaje del catálogo.
Un bloqueo no es un error HTTP
Esto es lo que más sorprende al integrar
Un mensaje bloqueado devuelve 200, no 4xx. Para el usuario final es indistinguible de una respuesta normal: recibe un texto y la conversación sigue.
- Widget y SDK — llegan los tokens del mensaje de bloqueo y luego el fin de turno, igual que cualquier respuesta.
onErrorno dispara. - HTTP — la respuesta trae además
security: { blocked: true, checkType: "..." }.
Si tu UI depende de detectar bloqueos, el único sitio donde se distinguen es ese campo de la respuesta HTTP. Por el canal público no se distingue, a propósito.
El texto que se devuelve nunca dice qué comprobación saltó. El motivo real solo queda en el registro de intercepciones del panel, para no darle a quien sondea un mapa de los filtros.
Límites de abuso
| Límite | Por defecto | Comportamiento |
|---|---|---|
| Longitud máxima | 2000 caracteres | Recorta en silencio, no rechaza |
| Mensajes por hora | Sin límite | Bloquea con mensaje de catálogo |
| Ráfaga | Desactivado | Bloquea mensajes demasiado seguidos |
La longitud recorta, no falla
Un mensaje más largo que el límite no se rechaza: se corta y se procesa el principio. Si tu aplicación permite pegar textos largos, valida tú la longitud antes de enviar, o el usuario verá una respuesta a media pregunta sin saber por qué.
Quién cuenta como "un cliente" a efectos de estos límites: en el widget y el SDK es una huella que el navegador guarda aparte y que no se reinicia al empezar conversación nueva — justo para que resetear no sirva para esquivar el límite. En la vía HTTP es el subjectId que tú envías.
Filtros de contenido
Cinco comprobaciones, en orden fijo. Las dos primeras son atajos: si pasan, se salta el resto.
| # | Comprobación | Qué hace |
|---|---|---|
| 1 | Frases seguras | Si el mensaje completo coincide con una frase de la lista, pasa directo |
| 2 | Solo emojis | Un mensaje sin texto pasa directo |
| 3 | Entropía | Detecta cargas ofuscadas (cadenas hexadecimales, ruido, leet excesivo) |
| 4 | Palabras prohibidas | Coincidencia literal, con detección leet y difusa opcionales |
| 5 | Firewall semántico | Compara el significado con frases de ejemplo, por similitud |
Las reglas son globales; los interruptores, por agente
Las listas de palabras, las frases seguras y las categorías del firewall se definen una vez para toda la instalación, en la sección Seguridad del panel. Lo que se elige por agente es cuáles de las cinco comprobaciones se aplican y qué texto se devuelve al bloquear.
Cada capa tiene en el panel un probador para pasarle un texto y ver qué habría saltado, sin gastar una llamada al modelo.
Los textos que ve el usuario
Todos los mensajes de bloqueo salen de un catálogo editable (Mensajes de plataforma): agente desactivado, límite por hora, ráfaga, entropía, proveedor saturado, error del modelo, y uno por cada categoría de palabras prohibidas y del firewall.
Se resuelven en este orden: texto propio del agente → texto global → constante de emergencia. Así que puedes dejar el global para toda la instalación y cambiar solo el de un agente concreto.
Las entradas se crean solas al arrancar; en el panel solo se editan los textos.
Requisito de infraestructura
Sin Redis no hay chat
Los contadores de los límites viven en Redis. Si Redis no está disponible, las rutas con rate limit devuelven 503 en vez de dejar pasar el tráfico — falla cerrado, a propósito. Tenlo presente al diagnosticar una caída: un 503 en /embed/* apunta a Redis, no al modelo.