Skip to main content

¿Qué es ctx.memory?

ctx.memory es un almacenamiento key-value por sesión respaldado por Redis. Está disponible automáticamente cuando la petición viene de una conversación activa (tiene socketId) y el company tiene una API key de workflow configurada. Casos de uso típicos:
  • Flujos multi-paso — recordar en qué paso está el usuario
  • Carritos de compras — acumular productos durante la conversación
  • Contadores — limitar intentos de login, tracking de reintentos
  • Preferencias temporales — idioma, formato, filtros durante la sesión

Inicio rápido

index.ts
import { define, z } from "@jelou/functions";

export default define({
  name: "flujo-registro",
  description: "Registro multi-paso con memoria de sesión",
  input: z.object({
    respuesta: z.string().optional(),
  }),
  handler: async (input, ctx) => {
    if (!ctx.memory.available) {
      return { error: "Memoria no disponible fuera de una conversación" };
    }

    const paso = await ctx.memory.get("paso", "inicio");

    if (paso === "inicio") {
      await ctx.memory.set("paso", "nombre", 3600);
      return { pregunta: "¿Cuál es tu nombre?" };
    }

    if (paso === "nombre") {
      await ctx.memory.set("nombre", input.respuesta || "", 3600);
      await ctx.memory.set("paso", "email", 3600);
      return { pregunta: "¿Cuál es tu email?" };
    }

    const nombre = await ctx.memory.get("nombre", "");
    await ctx.memory.delete("paso");
    await ctx.memory.delete("nombre");
    return { completado: true, nombre, email: input.respuesta };
  },
});

Verificar disponibilidad

if (!ctx.memory.available) {
  ctx.log("Memory no disponible — sin socketId o API key de workflow");
  return { error: "memory_unavailable" };
}
ctx.memory.available es false cuando falta el socketId (peticiones fuera de una conversación) o la API key del workflow no está configurada. Llamar a métodos en un cliente no disponible lanza un Error.

Primitivos vs JSON

Usa set()/get() para valores simples y setJson()/getJson() para objetos:
await ctx.memory.set("paso", "confirmacion", 3600);
const paso = await ctx.memory.get("paso", "inicio");

await ctx.memory.setJson("carrito", { items: [], total: 0 }, 86400);
const carrito = await ctx.memory.getJson("carrito", { items: [], total: 0 });
El tipo de retorno de get() coincide con el tipo del valor por defecto:
const nombre = await ctx.memory.get("nombre", "anónimo");     // string
const intentos = await ctx.memory.get("intentos", 0);           // number
const verificado = await ctx.memory.get("verificado", false);   // boolean

TTL (tiempo de vida)

Todos los valores expiran automáticamente. El TTL se especifica en segundos.
MétodoTTLMáximo
set()Opcional86,400 (24h)
setJson()Requerido86,400 (24h)
await ctx.memory.set("paso", "pago");                 // sin TTL explícito
await ctx.memory.set("paso", "pago", 1800);           // expira en 30 min
await ctx.memory.setJson("carrito", carrito, 86400);   // expira en 24h (máximo)

Límites

RestricciónValor
Longitud máxima de set()255 caracteres
TTL máximo86,400 segundos (24h)
AlcancePor sesión (socketId)
Valores de set() que excedan 255 caracteres lanzan un Error. Para datos más grandes, usa setJson().

Patrones comunes

handler: async (input, ctx) => {
  const paso = await ctx.memory.get("paso", "inicio");

  if (paso === "inicio") {
    await ctx.memory.set("paso", "datos", 3600);
    return { siguiente: "datos" };
  }

  if (paso === "datos") {
    await ctx.memory.set("nombre", input.nombre, 3600);
    await ctx.memory.set("paso", "confirmar", 3600);
    return { siguiente: "confirmar", nombre: input.nombre };
  }

  const nombre = await ctx.memory.get("nombre", "");
  await ctx.memory.delete("paso");
  await ctx.memory.delete("nombre");
  return { completado: true, nombre };
}

Manejo de errores

import { MemoryApiError } from "@jelou/functions";

try {
  await ctx.memory.set("paso", "pago", 3600);
} catch (err) {
  if (err instanceof MemoryApiError) {
    ctx.log("Memory API falló", { status: err.status, code: err.code });
    if (err.isRateLimit()) {
      return { error: "rate_limit", retryAfter: 2 };
    }
  }
  throw err;
}

¿Cuándo usar ctx.memory vs una base de datos?

ctx.memoryBase de datos externa
AlcancePor sesión (socketId)Global
PersistenciaTemporal (máx 24h)Permanente
ConfiguraciónCero — viene incluidoRequiere connection string en secrets
Ideal paraEstado de conversación, cache temporalDatos de usuario, historial, config

Referencia completa

Firma de cada método, tipos genéricos, MemoryApiError y mocks para testing.