Pular para o conteúdo principal

O que é ctx.memory?

ctx.memory é um armazenamento chave-valor por sessão baseado em Redis. Está disponível automaticamente quando a requisição vem de uma conversa ativa (possui um socketId) e a empresa tem uma chave de API de workflow configurada. Casos de uso típicos:
  • Fluxos multi-etapa — lembrar em qual etapa o usuário está
  • Carrinhos de compra — acumular produtos durante a conversa
  • Contadores — limitar tentativas de login, rastreamento de retentativas
  • Preferências temporárias — idioma, formato, filtros durante a sessão

Quick start

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

export default define({
  name: "registration-flow",
  description: "Multi-step registration with session memory",
  input: z.object({
    answer: z.string().optional(),
  }),
  handler: async (input, ctx) => {
    if (!ctx.memory.available) {
      return { error: "Memory not available outside of a conversation" };
    }

    const step = await ctx.memory.get("step", "start");

    if (step === "start") {
      await ctx.memory.set("step", "name", 3600);
      return { question: "Qual é o seu nome?" };
    }

    if (step === "name") {
      await ctx.memory.set("name", input.answer || "", 3600);
      await ctx.memory.set("step", "email", 3600);
      return { question: "Qual é o seu e-mail?" };
    }

    const name = await ctx.memory.get("name", "");
    await ctx.memory.delete("step");
    await ctx.memory.delete("name");
    return { completed: true, name, email: input.answer };
  },
});

Verificar disponibilidade

if (!ctx.memory.available) {
  ctx.log("Memory not available — no socketId or workflow API key");
  return { error: "memory_unavailable" };
}
ctx.memory.available é false quando o socketId está ausente (requisições fora de uma conversa) ou a chave de API de workflow não está configurada. Chamar métodos em um cliente indisponível lança um Error.

Primitivos vs JSON

Use set()/get() para valores simples e setJson()/getJson() para objetos:
await ctx.memory.set("step", "confirmation", 3600);
const step = await ctx.memory.get("step", "start");

await ctx.memory.setJson("cart", { items: [], total: 0 }, 86400);
const cart = await ctx.memory.getJson("cart", { items: [], total: 0 });
O tipo de retorno de get() corresponde ao tipo do valor padrão:
const name = await ctx.memory.get("name", "anonymous");   // string
const attempts = await ctx.memory.get("attempts", 0);     // number
const verified = await ctx.memory.get("verified", false); // boolean

TTL (time to live)

Todos os valores expiram automaticamente. O TTL é especificado em segundos.
MétodoTTLMáximo
set()Opcional86.400 (24h)
setJson()Obrigatório86.400 (24h)
await ctx.memory.set("step", "payment");                  // no explicit TTL
await ctx.memory.set("step", "payment", 1800);            // expires in 30 min
await ctx.memory.setJson("cart", cart, 86400);            // expires in 24h (maximum)

Limites

RestriçãoValor
Comprimento máximo de set()255 caracteres
TTL máximo86.400 segundos (24h)
EscopoPor sessão (socketId)
Valores de set() que excedem 255 caracteres lançam um Error. Para dados maiores, use setJson().

Padrões comuns

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

  if (step === "start") {
    await ctx.memory.set("step", "data", 3600);
    return { next: "data" };
  }

  if (step === "data") {
    await ctx.memory.set("name", input.name, 3600);
    await ctx.memory.set("step", "confirm", 3600);
    return { next: "confirm", name: input.name };
  }

  const name = await ctx.memory.get("name", "");
  await ctx.memory.delete("step");
  await ctx.memory.delete("name");
  return { completed: true, name };
}

Tratamento de erros

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

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

Quando usar ctx.memory vs um banco de dados?

ctx.memoryBanco de dados externo
EscopoPor sessão (socketId)Global
PersistênciaTemporária (máx 24h)Permanente
ConfiguraçãoZero — incluídoRequer connection string nos secrets
Ideal paraEstado da conversa, cache temporárioDados de usuários, histórico, config