Saltar al contenido
nvíame
Capítulo 2 de 514 min15 oct 2026

Bot de turnos con estados

Construye un bot que agenda turnos con una máquina de estados y pruébalo conversando.

Vamos a construir un bot que agenda turnos para una clínica. El flujo es corto pero tiene todo lo esencial: estados, validación de entrada, confirmación e intenciones globales.

Los estados

inicio ──"turno"──▶ pedir_dia ──día válido──▶ pedir_hora
                                                   │
                         confirmado ◀──"sí"── confirmar ◀──hora válida

Conversa con tu bot

El script registra un manejador con mx.bot.onMessage. Escribe en el campo del teléfono para hablar con él. Modifica las respuestas o agrega un estado nuevo; el bot se reinicia al editar.

// Bot de turnos: máquina de estados mínima
let step = "inicio";
const turno = {};
const DIAS = ["lunes", "martes", "miércoles", "jueves", "viernes"];

mx.bot.onMessage(({ text }) => {
  const t = text.trim().toLowerCase();

  if (t === "cancelar") {
    step = "inicio";
    return mx.bot.reply("Listo, cancelé el proceso. Escribe 'turno' para empezar de nuevo.");
  }

  if (step === "inicio") {
    if (t.includes("turno")) {
      step = "pedir_dia";
      return mx.bot.reply("¿Qué día prefieres? (lunes a viernes)");
    }
    return mx.bot.reply("Hola 👋 Escribe 'turno' para agendar.");
  }

  if (step === "pedir_dia") {
    if (!DIAS.includes(t)) return mx.bot.reply("No reconocí el día. Prueba con 'martes'.");
    turno.dia = t;
    step = "pedir_hora";
    return mx.bot.reply("Perfecto. ¿A qué hora? (9 a 17)");
  }

  if (step === "pedir_hora") {
    const h = parseInt(t, 10);
    if (!(h >= 9 && h <= 17)) return mx.bot.reply("Atendemos de 9 a 17. ¿Qué hora te acomoda?");
    turno.hora = h;
    step = "confirmar";
    return mx.bot.reply("¿Confirmas el " + turno.dia + " a las " + h + ":00? (sí/no)");
  }

  if (step === "confirmar") {
    step = "inicio";
    return mx.bot.reply(t.startsWith("s") ? "✅ Turno confirmado. Te enviaremos un recordatorio." : "Sin problema, no agendé nada.");
  }
});

mx.bot.reply("Hola 👋 Soy el asistente de la clínica. Escribe 'turno' para agendar.");

Persistir el estado

En el playground, step vive en memoria del worker. En producción vive en una base de datos o en un almacén clave-valor con TTL, indexado por usuario y canal, porque cada mensaje puede llegar a una instancia distinta de tu servicio.

Fíjate en que cada rama del bot valida la entrada antes de avanzar. Un bot que acepta cualquier cosa para no frustrar al usuario termina frustrándolo más tarde, cuando el turno queda registrado para un día que no existe.

Se completa automáticamente al leer el 80%.

Comentarios (3)

Diego Fernández15 oct 2026

¿Cómo manejo que el usuario escriba 'cancelar' en cualquier paso?

Equipo nvíameAutor15 oct 2026

Con intenciones globales evaluadas antes del estado actual: si el texto coincide con 'cancelar' o 'menú', se resuelven sin importar el paso. Así el usuario nunca queda atrapado.

Sofía Castillo15 oct 2026

Lo apliqué en el proyecto del trabajo. La sección «Bot de turnos con estados» me ahorró una discusión larga con el equipo: ahora tenemos un criterio compartido.

Valentina Muñoz15 oct 2026

¿Hay alguna diferencia importante si lo implemento en un servicio con varias instancias detrás de un balanceador?

Equipo nvíameAutor15 oct 2026

Sí: todo estado que hoy vive en memoria (contadores, sesiones, claves vistas) debe moverse a un almacén compartido con TTL, como Redis. Si no, cada instancia ve solo una parte de la historia.

Los comentarios se guardan solo en este navegador.