Ciclo de vida del runtime del canal
Los canales se sitúan en el borde de ZeroClaw. Se comunican con plataformas de chat, webhooks, editores y fuentes de eventos, y luego entregan trabajo normalizado al entorno de ejecución del agente.
Usa esta página cuando un cambio afecte a los listeners de canal, los webhooks del gateway, el envío de mensajes, la intención de respuesta, los borradores en streaming, la recarga por canal, el comportamiento de salud/reintento exponencial o el límite entre los adaptadores específicos de plataforma y el procesamiento de turnos a cargo del runtime.
Límite objetivo y transición actual
El límite objetivo es simple:
- Los adaptadores de canal gestionan la E/S específica de la plataforma.
- El código propiedad del tiempo de ejecución controla el ciclo de vida del turno del agente.
- Los controladores de webhooks de Gateway se encargan de los detalles genéricos de transporte HTTP y luego entran en el mismo ciclo de vida de turnos de canal que los oyentes de larga duración.
El código actual sigue en transición. zeroclaw-channels contiene un módulo orchestrator grande con ChannelRuntimeContext, run_message_dispatch_loop y process_channel_message. Ese código actualmente realiza tareas de tamaño de ejecución: enrutamiento de mensajes, hooks, protecciones contra bucles de autorreferencia, contexto pasivo, enriquecimiento de medios/enlaces, guardado automático, recuerdo de memoria, intención de respuesta, invocación del bucle de herramientas, actualizaciones de borradores, cancelación, acuses de recibo, seguimiento de costos y entrega final.
Ese es código funcional, no una razón para bloquear cada cambio de canal. La regla de revisión es más específica: el trabajo de nuevo canal, webhook o streaming debe reutilizar este ciclo de vida compartido cuando sea posible y no debe añadir otro miniorquestador local.
Qué posee qué
| Superficie | Propietario | Regla de revisión |
|---|---|---|
| Escuchador de plataforma o adaptador de entrada de canal | Módulo de canal o complemento de canal | Mantén las comprobaciones de firma, la decodificación de la carga útil, los reintentos de la plataforma, la verificación del proveedor, el manejo del desafío y la construcción de ChannelMessage dentro del adaptador de transporte. |
| Ruta de webhook de Gateway | Controlador de gateway | Mantén el alojamiento de rutas, el proxy, el comportamiento de tiempo de espera, el acuse de recibo rápido y la política genérica de respuesta HTTP locales al gateway. No amplíes allí el análisis nuevo específico de la plataforma, salvo como deuda de transición documentada. |
| Mensaje entrante normalizado | ChannelMessage de zeroclaw-api | Conserva el remitente, el destinatario de respuesta, el canal, el alias, el hilo, los adjuntos, el asunto, el contexto pasivo y el alcance de la conversación. Añade metadatos estructurados en lugar de ocultar las señales de enrutamiento en texto visible para el usuario. |
| Propiedad del agente para un alias de canal | start_channels / AgentRouter y enlaces de canal activos | Resuelve el agente propietario a partir de las vinculaciones configuradas. No recurras silenciosamente a un agente no relacionado cuando un canal no tenga propietario o esté deshabilitado. |
| Despacho y cancelación de mensajes | Bucle de despacho de canal compartido | Reutiliza el seguimiento en vuelo, /stop, la cancelación de remitente/hilo, los límites máximos en vuelo y la concurrencia de los trabajadores. |
| Iniciar el procesamiento | Ciclo de vida compartido del runtime/canal | Hooks, protección de auto-bucle, contexto pasivo, enriquecimiento de medios/enlaces, comandos en tiempo de ejecución, enrutamiento de modelos, guardado automático, recuperación de memoria, intención de respuesta, ejecución de herramientas, recibos, coste y entrega deben vivir en una sola ruta. |
| Confirmación del webhook de Gateway | Controlador de gateway | Los transportes Fast-ack pueden devolver HTTP 200 antes de que el modelo finalice, pero el trabajo en segundo plano aún debe entrar en el ciclo de vida del canal compartido. |
| Salud del canal y reconexión | Supervisor de oyentes | Los fallos reintentables del listener usan retroceso exponencial acotado y una finalización que tiene en cuenta la cancelación. Los fallos no reintentables deben detenerse o mostrarse con claridad. |
| Recarga en tiempo de ejecución | Ruta de recarga del daemon y reinicio del canal | Un guardado de configuración no es suficiente. Los listeners de larga ejecución solo adoptan los cambios de channel/provider/scheduler cuando el daemon se recarga o el proceso se reinicia. |
Forma de entrada
Los canales de larga duración y los canales respaldados por webhook tienen puntos de entrada de transporte diferentes, pero deberían converger en la misma forma de mensaje:
flowchart LR
A["Platform event"] --> B["Transport adapter"]
B --> C["ChannelMessage"]
C --> D["Channel dispatch loop"]
D --> E["Agent turn lifecycle"]
E --> F["Channel send / draft / reply"]
Los adaptadores deben conservar el trabajo que solo la plataforma puede entender:
- resolución de rutas y alias;
- límites de tamaño del cuerpo y decodificación;
- verificación de firma o token
- reglas de análisis específicas de la plataforma;
- emparejamiento, lista de अनुमति, o extracción de identidad del remitente;
- endpoints de desafío o verificación del proveedor;
- política de acuse de recibo inmediato
Después de eso, pasa un ChannelMessage normalizado. No copies el resto del ciclo de vida al adaptador a menos que la excepción sea estrecha, esté documentada y tenga pruebas.
Responsabilidades en tiempo de ejecución
El ciclo de vida compartido debe encargarse del comportamiento que debe ser consistente entre canales:
- hooks como message-received y message-sent;
- protección contra bucles de autocanales mediante
Channel::self_handle()ydrop_self_messages; - grabación de contexto pasivo sin efectos secundarios del modelo/proveedor;
- reacciones de acuse de recibo anticipado y limpieza de no respuesta;
- preprocesamiento de medios y enlaces antes de la llamada al proveedor;
- comandos de ejecución como
/new,/model,/models,/configy/stop; - claves de autoguardado e historial de sesión;
- recuperación de memoria y recorte del historial;
- clasificación de intención de respuesta para canales de grupo y ambientales
- actualizaciones de borrador en streaming y comportamiento de múltiples mensajes;
- aprobación de herramientas, ejecución, recibos, eventos de observador y seguimiento de costos;
- cancelación, timeout, rollback y entrega de la respuesta final.
Si una PR cambia una de esas responsabilidades solo para un canal, los revisores deberían preguntar si pertenece al ciclo de vida compartido o a los metadatos de capacidad del canal tipado.
Webhooks de Gateway
Los webhooks de Gateway tienen un requisito especial legítimo: la solicitud HTTP puede necesitar devolver una respuesta rápidamente incluso cuando el turno del agente es lento. Nextcloud Talk es el ejemplo más claro porque los modelos locales lentos pueden exceder los tiempos de espera de los webhooks del proveedor.
Ese requisito de acuse rápido no debería obligar al gateway a gestionar un ciclo de vida de agente independiente. Los controladores actuales respaldados por el gateway todavía usan una ruta de despacho específica del gateway posterior a la verificación. Considera eso deuda de migración y contexto de transición, no el patrón objetivo para nuevas implementaciones de canales basados en webhook. Un controlador de webhook sigue un orden fijo:
- verifica la solicitud;
- decodifica el payload;
- analiza uno o más valores de
ChannelMessage; - elija despacho síncrono o en segundo plano;
- devuelve la respuesta HTTP apropiada para el transporte.
Para los webhooks de canales que distribuyen mensajes, los pasos 1 y 4 son estructurales, no convencionales. El módulo webhook_ingress de la puerta de enlace gestiona un contrato de entrada autenticada:
- cada adaptador de webhook de envío de mensajes declara su modo de autenticación en un único registro (
MESSAGE_DISPATCHING_WEBHOOKS), y las pruebas de detección de desviaciones concilian la tabla de rutas de la puerta de enlace con ese registro; authenticateaplica la política de credenciales de fallo cerrado. Si falta un secreto requerido, está en blanco o no se puede resolver, la solicitud se rechaza con401antes de analizar cualquier byte de la carga útil. El algoritmo de firma y el formato de encabezado específicos del proveedor permanecen en el controlador de transporte, como un cierre que se ejecuta solo después de resolver la credencial;- una comprobación exitosa acuña una prueba
VerifiedWebhookIngressque contiene los bytes verificados. Consumirparse_messagesproporciona al analizador esos bytes exactos y devuelve un valor privadoVerifiedWebhookMessages. Ninguna de las dos pruebas se puede construir ni clonar en otro lugar; dispatch_verified_webhookes el auxiliar compartido de gateway-webhook para el registro de entrada actual, la clave de sesión, el guardado automático, el envío al agente, el fallback de quickstart, la entrega de respuestas/errores y la ejecución síncrona o con acuse rápido. Consume la prueba analizada, por lo que el contenido del webhook no puede entrar en el envío al agente sin un resultado de verificación y un paso de análisis vinculados a la misma solicitud.
Ese helper elimina las cadenas duplicadas de parse -> autosave -> chat -> send de la gateway y proporciona a la entrada autenticada un único punto de control obligatorio. Sin embargo, sigue llamando a la ruta de chat de la gateway, por lo que no es el ciclo de vida compartido de los turnos de canal descrito anteriormente. Los webhooks de la gateway todavía deben converger en ese ciclo de vida para los hooks, el control de bucles propios, el contexto pasivo, el procesamiento de medios y enlaces, los comandos en tiempo de ejecución, la cancelación, la intención de respuesta, las confirmaciones de recepción y el seguimiento de costes. Esta convergencia futura debe preservar la garantía de entrada autenticada y el comportamiento de respuesta síncrona o de acuse rápido de cada transporte.
Todos los adaptadores de webhook que distribuyen mensajes en el registro declaran una credencial obligatoria por alias y se rechazan antes del análisis cuando dicha credencial falta, está vacía o no se puede resolver. El registro no tiene un modo de verificación opcional: la omisión silenciosa no es un modo de autenticación. Por tanto, actualmente no se puede registrar como adaptador de distribución de mensajes un adaptador sin mecanismo de credenciales entrantes; añadir uno requeriría ampliar el registro con una política explícita de solo rechazo, en lugar de relajar la verificación.
Al revisar cambios de webhook, compara por separado los controladores síncronos y los controladores de acuse rápido:
- los controladores síncronos deben conservar los códigos de estado existentes, el comportamiento de firma no válida, las claves de guardado automático y la entrega de respuestas;
- Los controladores fast-ack deben demostrar que la confirmación HTTP ocurre antes de que la llamada al modelo pueda bloquear el tiempo de espera del proveedor;
- aunque se mantenga la ruta específica de la pasarela, ambas estructuras deben entrar en el despacho a través de
dispatch_verified_webhooken lugar de añadir otra cadenaparse -> autosave -> chat -> send. Un inventario fijado de sitios de llamada hace que la compilación falle cuando un controlador omite el flujo autenticado. Este requisito no convierte al auxiliar en el ciclo de vida del canal de destino.
Recarga y ciclo de vida del listener
La configuración del canal puede guardarse antes de que el listener en ejecución la vea. El daemon es propietario del grafo de subsistemas de larga duración, por lo que los cambios del listener del canal se aplican cuando el daemon recarga o reinicia el subsistema relevante. Los inicios del gateway independiente pueden requerir reiniciar el proceso para los cambios del listener del canal.
Revisa los cambios sensibles a la recarga comprobando:
- si el valor cambiado se guarda en
config.toml; - si el contexto del canal en ejecución lee el nuevo valor inmediatamente, al recargar o solo después de reiniciar;
- si las tareas de escucha se detienen mediante cancelación en lugar de dejar conexiones antiguas huérfanas;
- si los enlaces de canal activos siguen siendo la fuente de verdad sobre qué agente posee cada alias de canal.
Transmisión, borradores y cancelación
Streaming es un límite de capacidades. Un canal puede admitir ediciones de borrador, streaming de múltiples mensajes, indicadores de escritura o solo el comportamiento de envío final. El ciclo de vida compartido decide cómo se usan esas capacidades durante un turno.
Revisar los cambios de streaming preguntando:
- ¿El canal declara la capacidad en lugar de codificar el comportamiento en el bucle de turnos?
- ¿Los mensajes borrador se finalizan, cancelan o reemplazan en cada ruta de éxito, sin respuesta, fallo y cancelación?
- ¿
/stopcancela el ámbito correcto de remitente/hilo? - ¿Las vueltas interrumpidas evitan persistir una respuesta parcial del asistente como si estuviera completa?
- ¿se mantiene consistente el comportamiento visible para el usuario en mensajes directos, chats grupales y respuestas en hilos?
Salud y retroceso
Los listeners de larga ejecución deben fallar de una manera que los operadores puedan entender. Los fallos de plataforma reintentables deben aplicar retroceso y reintentar; los fallos de configuración o autenticación no reintentables deben mostrarse claramente en lugar de entrar en un bucle infinito.
Para los cambios de listener, demuestra la ruta relevante:
- cierre limpio del listener al cancelar;
- fallo recuperable de la API retrocede y reanuda;
- un fallo no reintentable detiene o informa de un problema de configuración duradero;
- un canal bloqueado no atasca a los oyentes hermanos ni la entrega al observador.
Lista de verificación para revisores
Para cambios de channel, webhook o channel-runtime, responde a estas preguntas antes de la aprobación del revisor:
- ¿Qué trabajo específico del transporte queda en el adaptador y por qué?
- ¿Dónde crea o recibe el código por primera vez un
ChannelMessage? - ¿Qué agente posee el alias del canal para este mensaje?
- ¿El cambio reutiliza el despacho compartido y el ciclo de vida de giro?
- Si agrega comportamiento de ciclo de vida específico del canal, ¿qué hook o capacidad compartida se consideró y por qué no es suficiente?
- ¿Cómo se transportan self-loop, addressedness, passive context e intent de respuesta?
- ¿Están acotados los medios, enlaces, adjuntos y salidas de herramientas antes de entrar en el contexto visible para el proveedor?
- ¿La confirmación rápida, si la hay, sigue preservando el mismo comportamiento de giro en segundo plano que el despacho síncrono?
- ¿Qué ocurre en la recarga, la cancelación del listener, el tiempo de espera del proveedor,
/stop, sin respuesta y el fallo de envío? - ¿Qué prueba focalizada o verificación manual de humo demuestra el límite que cambió?
Punteros de origen
Documentación canónica:
- Ciclo de vida de la solicitud
- Estado de ejecución y persistencia
- Memoria y ciclo de vida de la carga útil
- Ciclo de vida de configuración
- Resumen de canales
- API HTTP de la gateway
- FND-001: Arquitectura intencional
- Protocolo del plugin
Puntos de entrada clave del código:
- Trait de canal y forma del mensaje:
crates/zeroclaw-api/src/channel.rs - ABI del contexto de entrada:
crates/zeroclaw-api/src/ingress.rs - Despacho de canales y ciclo de vida de turnos:
crates/zeroclaw-channels/src/orchestrator/mod.rs - Bucle de ejecución por turno:
crates/zeroclaw-runtime/src/agent/turn/ - Punto de entrada genérico del proceso en tiempo de ejecución:
crates/zeroclaw-runtime/src/agent/loop_.rs - Ruta de webhook/chat de Gateway:
crates/zeroclaw-gateway/src/lib.rs