Cola de comandos (2026-01-16)

Serializamos las ejecuciones de auto-respuesta entrantes (todos los canales) a través de una pequeña cola en proceso para evitar que múltiples ejecuciones del agente colisionen, sin dejar de permitir paralelismo seguro entre sesiones.

Por qué

  • Las ejecuciones de auto-respuesta pueden ser costosas (llamadas LLM) y pueden colisionar cuando llegan múltiples mensajes entrantes casi al mismo tiempo.
  • La serialización evita competir por recursos compartidos (archivos de sesión, logs, stdin del CLI) y reduce la probabilidad de límites de tasa del upstream.

Cómo funciona

  • Una cola FIFO con carriles drena cada carril con un tope de concurrencia configurable (por defecto 1 para carriles no configurados; main tiene por defecto 4, subagent 8).
  • runEmbeddedPiAgent encola por clave de sesión (carril session:<key>) para garantizar solo una ejecución activa por sesión.
  • Cada ejecución de sesión se encola luego en un carril global (main por defecto) para que el paralelismo total esté limitado por agents.defaults.maxConcurrent.
  • Cuando el logging verboso está habilitado, las ejecuciones encoladas emiten un aviso breve si esperaron más de ~2s antes de iniciar.
  • Los indicadores de escritura se disparan inmediatamente al encolar (cuando el canal lo soporta) para que la experiencia de usuario no cambie mientras esperamos nuestro turno.

Modos de cola (por canal)

Los mensajes entrantes pueden dirigir la ejecución actual, esperar un turno de seguimiento, o ambos:

  • steer: inyectar inmediatamente en la ejecución actual (cancela llamadas de herramientas pendientes después del siguiente límite de herramienta). Si no hay streaming, recurre a followup.
  • followup: encolar para el siguiente turno del agente después de que termine la ejecución actual.
  • collect: fusionar todos los mensajes encolados en un único turno de seguimiento (por defecto). Si los mensajes apuntan a diferentes canales/hilos, se drenan individualmente para preservar el enrutamiento.
  • steer-backlog (también steer+backlog): dirigir ahora y preservar el mensaje para un turno de seguimiento.
  • interrupt (legacy): abortar la ejecución activa para esa sesión, luego ejecutar el mensaje más nuevo.
  • queue (alias legacy): igual que steer.

Steer-backlog significa que puedes recibir una respuesta de seguimiento después de la ejecución dirigida, así que las superficies de streaming pueden parecer duplicados. Prefiere collect/steer si quieres una respuesta por mensaje entrante. Envía /queue collect como comando independiente (por sesión) o configura messages.queue.byChannel.discord: "collect".

Valores por defecto (cuando no se configura):

  • Todas las superficies → collect

Configura globalmente o por canal mediante messages.queue:

{
  messages: {
    queue: {
      mode: "collect",
      debounceMs: 1000,
      cap: 20,
      drop: "summarize",
      byChannel: { discord: "collect" },
    },
  },
}

Opciones de cola

Las opciones aplican a followup, collect y steer-backlog (y a steer cuando recurre a followup):

  • debounceMs: esperar silencio antes de iniciar un turno de seguimiento (previene “continue, continue”).
  • cap: máximo de mensajes encolados por sesión.
  • drop: política de desbordamiento (old, new, summarize).

Summarize mantiene una breve lista con viñetas de los mensajes descartados y la inyecta como un prompt de seguimiento sintético. Valores por defecto: debounceMs: 1000, cap: 20, drop: summarize.

Sobreescrituras por sesión

  • Envía /queue <mode> como comando independiente para almacenar el modo para la sesión actual.
  • Las opciones se pueden combinar: /queue collect debounce:2s cap:25 drop:summarize
  • /queue default o /queue reset limpia la sobreescritura de sesión.

Alcance y garantías

  • Aplica a ejecuciones de agente de auto-respuesta en todos los canales entrantes que usan el pipeline de respuesta del gateway (WhatsApp web, Telegram, Slack, Discord, Signal, iMessage, webchat, etc.).
  • El carril por defecto (main) es para todo el proceso para entrantes + heartbeats principales; configura agents.defaults.maxConcurrent para permitir múltiples sesiones en paralelo.
  • Pueden existir carriles adicionales (por ejemplo, cron, subagent) para que los trabajos en segundo plano se ejecuten en paralelo sin bloquear las respuestas entrantes.
  • Los carriles por sesión garantizan que solo una ejecución de agente toque una sesión dada a la vez.
  • Sin dependencias externas ni hilos de worker en segundo plano; puro TypeScript + promesas.

Solución de problemas

  • Si los comandos parecen atascados, habilita los logs verbosos y busca líneas “queued for …ms” para confirmar que la cola se está drenando.
  • Si necesitas la profundidad de la cola, habilita los logs verbosos y observa las líneas de tiempo de la cola.