Gestión de sesiones

OpenClaw trata una sesión de chat directo por agente como primaria. Los chats directos se colapsan a agent:<agentId>:<mainKey> (por defecto main), mientras que los chats de grupo/canal obtienen sus propias claves. Se respeta session.mainKey.

Usa session.dmScope para controlar cómo se agrupan los mensajes directos:

  • main (por defecto): todos los DMs comparten la sesión principal para mantener continuidad.
  • per-peer: aislar por id de remitente a través de canales.
  • per-channel-peer: aislar por canal + remitente (recomendado para bandejas de entrada multi-usuario).
  • per-account-channel-peer: aislar por cuenta + canal + remitente (recomendado para bandejas de entrada multi-cuenta). Usa session.identityLinks para mapear ids de pares con prefijo de proveedor a una identidad canónica para que la misma persona comparta una sesión de DM entre canales cuando uses per-peer, per-channel-peer o per-account-channel-peer.

Modo de DM seguro (recomendado para configuraciones multi-usuario)

Advertencia de seguridad: Si tu agente puede recibir DMs de múltiples personas, deberías considerar seriamente habilitar el modo de DM seguro. Sin él, todos los usuarios comparten el mismo contexto de conversación, lo que puede filtrar información privada entre usuarios.

Ejemplo del problema con la configuración por defecto:

  • Alice (<SENDER_A>) le envía un mensaje a tu agente sobre un tema privado (por ejemplo, una cita médica)
  • Bob (<SENDER_B>) le envía un mensaje a tu agente preguntando “¿De qué estábamos hablando?”
  • Como ambos DMs comparten la misma sesión, el modelo puede responderle a Bob usando el contexto previo de Alice.

La solución: Configura dmScope para aislar sesiones por usuario:

// ~/.openclaw/openclaw.json
{
  session: {
    // Modo DM seguro: aislar contexto de DM por canal + remitente.
    dmScope: "per-channel-peer",
  },
}

Cuándo habilitarlo:

  • Tienes aprobaciones de emparejamiento para más de un remitente
  • Usas una lista de permitidos de DM con múltiples entradas
  • Configuras dmPolicy: "open"
  • Múltiples números de teléfono o cuentas pueden enviar mensajes a tu agente

Notas:

  • El valor por defecto es dmScope: "main" para continuidad (todos los DMs comparten la sesión principal). Esto está bien para configuraciones de un solo usuario.
  • El onboarding local del CLI escribe session.dmScope: "per-channel-peer" por defecto cuando no está configurado (los valores explícitos existentes se preservan).
  • Para bandejas de entrada multi-cuenta en el mismo canal, prefiere per-account-channel-peer.
  • Si la misma persona te contacta en múltiples canales, usa session.identityLinks para colapsar sus sesiones de DM en una única identidad canónica.
  • Puedes verificar tu configuración de DM con openclaw security audit (ver security).

El gateway es la fuente de verdad

Todo el estado de sesión es propiedad del gateway (el OpenClaw “maestro”). Los clientes de UI (app de macOS, WebChat, etc.) deben consultar al gateway para listas de sesiones y conteos de tokens en lugar de leer archivos locales.

  • En modo remoto, el store de sesiones que importa reside en el host del gateway remoto, no en tu Mac.
  • Los conteos de tokens mostrados en las UIs provienen de los campos del store del gateway (inputTokens, outputTokens, totalTokens, contextTokens). Los clientes no parsean transcripciones JSONL para “corregir” totales.

Dónde reside el estado

  • En el host del gateway:
    • Archivo de store: ~/.openclaw/agents/<agentId>/sessions/sessions.json (por agente).
  • Transcripciones: ~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl (las sesiones de temas de Telegram usan .../<SessionId>-topic-<threadId>.jsonl).
  • El store es un mapa sessionKey -> { sessionId, updatedAt, ... }. Eliminar entradas es seguro; se recrean bajo demanda.
  • Las entradas de grupo pueden incluir displayName, channel, subject, room y space para etiquetar sesiones en las UIs.
  • Las entradas de sesión incluyen metadatos origin (etiqueta + hints de enrutamiento) para que las UIs puedan explicar de dónde vino una sesión.
  • OpenClaw no lee carpetas de sesión legacy de Pi/Tau.

Mantenimiento

OpenClaw aplica mantenimiento al store de sesiones para mantener sessions.json y los artefactos de transcripción acotados a lo largo del tiempo.

Valores por defecto

  • session.maintenance.mode: warn
  • session.maintenance.pruneAfter: 30d
  • session.maintenance.maxEntries: 500
  • session.maintenance.rotateBytes: 10mb
  • session.maintenance.resetArchiveRetention: por defecto igual a pruneAfter (30d)
  • session.maintenance.maxDiskBytes: sin configurar (deshabilitado)
  • session.maintenance.highWaterBytes: por defecto 80% de maxDiskBytes cuando el presupuesto está habilitado

Cómo funciona

El mantenimiento se ejecuta durante las escrituras del store de sesiones, y puedes activarlo bajo demanda con openclaw sessions cleanup.

  • mode: "warn": reporta qué se desalojaría pero no muta entradas/transcripciones.
  • mode: "enforce": aplica limpieza en este orden:
    1. podar entradas antiguas más viejas que pruneAfter
    2. limitar el conteo de entradas a maxEntries (las más antiguas primero)
    3. archivar archivos de transcripción para entradas eliminadas que ya no están referenciadas
    4. purgar archivos antiguos *.deleted.<timestamp> y *.reset.<timestamp> según la política de retención
    5. rotar sessions.json cuando excede rotateBytes
    6. si maxDiskBytes está configurado, aplicar presupuesto de disco hacia highWaterBytes (artefactos más antiguos primero, luego sesiones más antiguas)

Advertencia de rendimiento para stores grandes

Los stores de sesiones grandes son comunes en configuraciones de alto volumen. El trabajo de mantenimiento es trabajo en la ruta de escritura, así que stores muy grandes pueden aumentar la latencia de escritura.

Lo que más aumenta el costo:

  • valores muy altos de session.maintenance.maxEntries
  • ventanas largas de pruneAfter que mantienen entradas obsoletas
  • muchos artefactos de transcripción/archivo en ~/.openclaw/agents/<agentId>/sessions/
  • habilitar presupuestos de disco (maxDiskBytes) sin límites razonables de poda/tope

Qué hacer:

  • usa mode: "enforce" en producción para que el crecimiento se acote automáticamente
  • configura tanto límites de tiempo como de conteo (pruneAfter + maxEntries), no solo uno
  • configura maxDiskBytes + highWaterBytes para límites superiores estrictos en despliegues grandes
  • mantén highWaterBytes significativamente por debajo de maxDiskBytes (el valor por defecto es 80%)
  • ejecuta openclaw sessions cleanup --dry-run --json después de cambios de configuración para verificar el impacto proyectado antes de aplicar
  • para sesiones activas frecuentes, pasa --active-key al ejecutar limpieza manual

Ejemplos de personalización

Usar una política de aplicación conservadora:

{
  session: {
    maintenance: {
      mode: "enforce",
      pruneAfter: "45d",
      maxEntries: 800,
      rotateBytes: "20mb",
      resetArchiveRetention: "14d",
    },
  },
}

Habilitar un presupuesto de disco estricto para el directorio de sesiones:

{
  session: {
    maintenance: {
      mode: "enforce",
      maxDiskBytes: "1gb",
      highWaterBytes: "800mb",
    },
  },
}

Ajustar para instalaciones más grandes (ejemplo):

{
  session: {
    maintenance: {
      mode: "enforce",
      pruneAfter: "14d",
      maxEntries: 2000,
      rotateBytes: "25mb",
      maxDiskBytes: "2gb",
      highWaterBytes: "1.6gb",
    },
  },
}

Previsualizar o forzar mantenimiento desde CLI:

openclaw sessions cleanup --dry-run
openclaw sessions cleanup --enforce

Poda de sesión

OpenClaw recorta resultados antiguos de herramientas del contexto en memoria justo antes de las llamadas LLM por defecto. Esto no reescribe el historial JSONL. Ver /concepts/session-pruning.

Flush de memoria pre-compactación

Cuando una sesión se acerca a la auto-compactación, OpenClaw puede ejecutar un turno silencioso de flush de memoria que le recuerda al modelo escribir notas durables a disco. Esto solo se ejecuta cuando el workspace es de escritura. Ver Memory y Compaction.

Mapeo de transportes → claves de sesión

  • Los chats directos siguen session.dmScope (por defecto main).
    • main: agent:<agentId>:<mainKey> (continuidad entre dispositivos/canales).
      • Múltiples números de teléfono y canales pueden mapear a la misma clave principal del agente; actúan como transportes hacia una conversación.
    • per-peer: agent:<agentId>:direct:<peerId>.
    • per-channel-peer: agent:<agentId>:<channel>:direct:<peerId>.
    • per-account-channel-peer: agent:<agentId>:<channel>:<accountId>:direct:<peerId> (accountId por defecto es default).
    • Si session.identityLinks coincide con un id de par con prefijo de proveedor (por ejemplo telegram:123), la clave canónica reemplaza <peerId> para que la misma persona comparta una sesión entre canales.
  • Los chats grupales aíslan el estado: agent:<agentId>:<channel>:group:<id> (las salas/canales usan agent:<agentId>:<channel>:channel:<id>).
    • Los temas de foro de Telegram agregan :topic:<threadId> al id del grupo para aislamiento.
    • Las claves legacy group:<id> aún se reconocen para migración.
  • Los contextos entrantes pueden seguir usando group:<id>; el canal se infiere de Provider y se normaliza a la forma canónica agent:<agentId>:<channel>:group:<id>.
  • Otras fuentes:
    • Trabajos cron: cron:<job.id>
    • Webhooks: hook:<uuid> (a menos que el hook lo configure explícitamente)
    • Ejecuciones de nodo: node-<nodeId>

Ciclo de vida

  • Política de reinicio: las sesiones se reutilizan hasta que expiran, y la expiración se evalúa en el siguiente mensaje entrante.
  • Reinicio diario: por defecto a las 4:00 AM hora local del host del gateway. Una sesión está obsoleta cuando su última actualización es anterior al tiempo de reinicio diario más reciente.
  • Reinicio por inactividad (opcional): idleMinutes agrega una ventana deslizante de inactividad. Cuando están configurados tanto el reinicio diario como el de inactividad, el que expire primero fuerza una nueva sesión.
  • Inactividad legacy: si configuras session.idleMinutes sin ninguna configuración de session.reset/resetByType, OpenClaw permanece en modo solo-inactividad por compatibilidad retroactiva.
  • Sobreescrituras por tipo (opcional): resetByType te permite sobreescribir la política para sesiones direct, group y thread (thread = hilos de Slack/Discord, temas de Telegram, hilos de Matrix cuando los provee el conector).
  • Sobreescrituras por canal (opcional): resetByChannel sobreescribe la política de reinicio para un canal (aplica a todos los tipos de sesión para ese canal y tiene precedencia sobre reset/resetByType).
  • Disparadores de reinicio: /new o /reset exacto (más los extras en resetTriggers) inician un nuevo id de sesión y pasan el resto del mensaje. /new <model> acepta un alias de modelo, provider/model o nombre de proveedor (coincidencia difusa) para configurar el modelo de la nueva sesión. Si /new o /reset se envían solos, OpenClaw ejecuta un breve turno de saludo “hello” para confirmar el reinicio.
  • Reinicio manual: elimina claves específicas del store o borra la transcripción JSONL; el siguiente mensaje las recrea.
  • Los trabajos cron aislados siempre crean un sessionId nuevo por ejecución (sin reutilización por inactividad).

Política de envío (opcional)

Bloquear entrega para tipos de sesión específicos sin listar ids individuales.

{
  session: {
    sendPolicy: {
      rules: [
        { action: "deny", match: { channel: "discord", chatType: "group" } },
        { action: "deny", match: { keyPrefix: "cron:" } },
        // Coincide con la clave de sesión cruda (incluyendo el prefijo `agent:<id>:`).
        { action: "deny", match: { rawKeyPrefix: "agent:main:discord:" } },
      ],
      default: "allow",
    },
  },
}

Sobreescritura en runtime (solo propietario):

  • /send on → permitir para esta sesión
  • /send off → denegar para esta sesión
  • /send inherit → limpiar sobreescritura y usar reglas de configuración Envía estos como mensajes independientes para que se registren.

Configuración (ejemplo de renombrado opcional)

// ~/.openclaw/openclaw.json
{
  session: {
    scope: "per-sender", // mantener claves de grupo separadas
    dmScope: "main", // continuidad de DM (configura per-channel-peer/per-account-channel-peer para bandejas compartidas)
    identityLinks: {
      alice: ["telegram:123456789", "discord:987654321012345678"],
    },
    reset: {
      // Valores por defecto: mode=daily, atHour=4 (hora local del host del gateway).
      // Si también configuras idleMinutes, el que expire primero gana.
      mode: "daily",
      atHour: 4,
      idleMinutes: 120,
    },
    resetByType: {
      thread: { mode: "daily", atHour: 4 },
      direct: { mode: "idle", idleMinutes: 240 },
      group: { mode: "idle", idleMinutes: 120 },
    },
    resetByChannel: {
      discord: { mode: "idle", idleMinutes: 10080 },
    },
    resetTriggers: ["/new", "/reset"],
    store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
    mainKey: "main",
  },
}

Inspección

  • openclaw status — muestra la ruta del store y sesiones recientes.
  • openclaw sessions --json — vuelca todas las entradas (filtra con --active <minutes>).
  • openclaw gateway call sessions.list --params '{}' — obtiene sesiones del gateway en ejecución (usa --url/--token para acceso remoto al gateway).
  • Envía /status como mensaje independiente en el chat para ver si el agente es alcanzable, cuánto contexto de sesión se usa, los toggles actuales de thinking/fast/verbose, y cuándo se refrescaron por última vez tus credenciales de WhatsApp web (ayuda a detectar necesidades de re-enlace).
  • Envía /context list o /context detail para ver qué hay en el system prompt y los archivos de workspace inyectados (y los mayores contribuyentes al contexto).
  • Envía /stop (o frases de aborto independientes como stop, stop action, stop run, stop openclaw) para abortar la ejecución actual, limpiar seguimientos encolados para esa sesión y detener cualquier ejecución de sub-agente generada desde ella (la respuesta incluye el conteo de detenidas).
  • Envía /compact (instrucciones opcionales) como mensaje independiente para resumir contexto antiguo y liberar espacio en la ventana. Ver /concepts/compaction.
  • Las transcripciones JSONL se pueden abrir directamente para revisar turnos completos.

Consejos

  • Mantén la clave primaria dedicada al tráfico 1:1; deja que los grupos mantengan sus propias claves.
  • Al automatizar limpieza, elimina claves individuales en lugar del store completo para preservar contexto en otros lugares.

Metadatos de origen de sesión

Cada entrada de sesión registra de dónde vino (mejor esfuerzo) en origin:

  • label: etiqueta legible (resuelta desde la etiqueta de conversación + subject/canal del grupo)
  • provider: id de canal normalizado (incluyendo extensiones)
  • from/to: ids de enrutamiento crudos del sobre entrante
  • accountId: id de cuenta del proveedor (cuando es multi-cuenta)
  • threadId: id de hilo/tema cuando el canal lo soporta Los campos de origen se rellenan para mensajes directos, canales y grupos. Si un conector solo actualiza el enrutamiento de entrega (por ejemplo, para mantener fresca una sesión principal de DM), igual debe proporcionar contexto entrante para que la sesión mantenga sus metadatos explicativos. Las extensiones pueden hacer esto enviando ConversationLabel, GroupSubject, GroupChannel, GroupSpace y SenderName en el contexto entrante y llamando a recordSessionMetaFromInbound (o pasando el mismo contexto a updateLastRoute).