Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Cycle de vie de la requête

Ce qui se passe entre « l’utilisateur envoie un message » et « l’agent répond » : le chemin complet, avec annotations sur le streaming, les appels d’outils et les barrières de sécurité.

Entrant

flowchart LR
    A[External event] -->|webhook / push / poll / WS| B[Channel adapter]
    B -->|decode, dedup, pair-check| C[Inbound envelope]
    C -->|workspace binding| D[Runtime: process_message]

Un adaptateur de canal (par exemple discord.rs, telegram.rs, email_channel.rs) reçoit des événements natifs à la plateforme et les convertit en une enveloppe d’entrée uniforme. L’adaptateur gère :

  • Décodage : payload spécifique à la plateforme → format de message canonique
  • Déduplication : empêche de rejouer deux fois le même message (redémarrages, nouvelles tentatives)
  • Vérification par paire : applique la politique [channels.<name>.allowed_users] / IAM avant que l’événement n’atteigne le runtime

Si le canal n’est pas appairé ou si l’utilisateur n’est pas autorisé, l’événement est supprimé avant que le runtime ne le voie.

Boucle d’agent

sequenceDiagram
    participant CH as Channel
    participant RT as Runtime
    participant SEC as Security
    participant MEM as Memory / history
    participant PR as Provider
    participant TL as Tool

    CH->>RT: process_message(envelope)
    Note over RT: resolve memory-inject policy from the turn's TurnOrigin
    RT->>MEM: recall(query, session scopes)
    MEM-->>RT: entries
    Note over RT: render [Memory context] preamble (engine-side)
    RT->>PR: chat(system, history, tools)
    loop Streaming
        PR-->>RT: StreamEvent::TextDelta
        RT-->>CH: draft update (if channel supports it)
    end
    PR-->>RT: StreamEvent::ToolCall(args)
    RT->>SEC: evaluate_tool_access(name, args, risk)
    alt Blocked
        SEC-->>RT: Err(reason)
        RT->>PR: chat(..., + tool_error)
    else Approval required
        SEC->>CH: ask_operator(prompt)
        CH-->>SEC: approved / denied
    else Allowed
        SEC-->>RT: Ok
    end
    RT->>TL: invoke(args)
    TL-->>RT: ToolResult
    RT->>MEM: append to turn/session history
    RT->>PR: chat(..., + tool_result)
    PR-->>RT: StreamEvent::TextDelta (final)
    RT-->>CH: reply(final)
    RT->>MEM: persist conversation/session history

Propriétés clés :

  • Le streaming est de bout en bout. Le fournisseur diffuse des jetons. Si l’adaptateur de canal indique supports_draft_updates(), l’exécution modifie un message envoyé en place au fur et à mesure que le texte arrive. Discord, Slack et Telegram prennent en charge cette fonctionnalité.
  • Les appels d’outils sont transmis en continu. Le modèle peut émettre un appel d’outil alors qu’il génère encore du texte. L’environnement d’exécution lit le flux jusqu’à son terme, affiche le texte visible au fur et à mesure de son arrivée, puis récupère les appels d’outils, les valide, les exécute, renvoie le résultat et démarre un nouveau flux pour le tour suivant.
  • La complétion en streaming suit les événements du protocole. Les fournisseurs considèrent un flux réussi comme terminé à l’arrivée de son événement SSE terminal, plutôt que d’attendre que le serveur ferme la connexion. Les corps de réponse silencieux échouent après l’expiration du délai d’inactivité en octets du fournisseur, tandis que les générations actives peuvent dépasser le délai d’expiration des requêtes sans streaming.
  • La sécurité contrôle chaque appel d’outil. evaluate_tool_access consulte le niveau d’autonomie, les listes d’autorisation/de refus et les limites de chemins. Les appels à risque moyen sous l’autonomie Supervised passent par le circuit d’approbation de l’opérateur.
  • Le contexte mémoire est injecté par le moteur. Avant le premier appel fournisseur, le moteur de tour résout une politique d’injection à partir du TurnOrigin du tour (l’initiateur du tour) : les sous-tours imbriqués n’injectent jamais, les origines planifiées (cron, daemon) injectent en excluant les entrées de catégorie de conversation, et les origines côté utilisateur injectent (en excluant les entrées de conversation lorsque le tour n’a pas de portée de session). Un site de spawn peut supprimer l’injection pour toute origine (par exemple une tâche cron avec uses_memory = false), et les tours ne disposant d’aucun backend mémoire le sautent entièrement. Un seul rendu applique la décroissance temporelle, le filtrage de pertinence, un ensemble de sauts anti-empoisonnement de prompt et des plafonds de budget uniformément sur chaque chemin ; les backends mémoire ne répondent qu’à recall, ils ne formatent pas le contexte.
  • L’historique et la mémoire sont distincts. L’historique de session préserve la continuité des conversations, des appels d’outils et des résultats d’outils. Les écritures explicites en mémoire persistent les entrées sélectionnées dans le backend de mémoire. Les accusés de réception sont transmis in-band dans le texte de la conversation, plutôt que sous la forme d’un artefact persistant distinct. Pour plus de détails sur la propriété des payloads, consultez Cycle de vie de la mémoire et des payloads.

Reçus d’outils

Les exécutions d’outils réussies peuvent recevoir un reçu HMAC-SHA256 qui est ajouté au texte du résultat d’outil et renvoyé au modèle dans la conversation, prouvant que le résultat signé provient du runtime. Le HMAC utilise une clé éphémère en mémoire et est calculé sur tool_name || args || result || timestamp. Les reçus ne sont pas écrits dans un journal distinct sur disque et ne sont pas chaînés ; le modèle peut les renvoyer mais ne peut pas en forger un nouveau valide sans la clé. Voir Reçus d’outils.

Sortant

Les messages sortants repassent par le même adaptateur de canal. Les adaptateurs prenant en charge les messages multiples (Discord, Slack) peuvent diffuser de longues réponses sous forme d’une séquence de messages ; les autres (email, SMS) sont vidés à la fin du flux.

Où il se trouve dans le code

  • Boucle d’agent : crates/zeroclaw-runtime/src/agent/turn/ (run_tool_call_loop), avec les points d’entrée dans crates/zeroclaw-runtime/src/agent/loop_.rs (process_message, run)
  • Injection de contexte mémoire : crates/zeroclaw-runtime/src/agent/memory_inject.rs (resolve_inject_policy, render_memory_context), indexée sur TurnOrigin des types d’entrée de zeroclaw-api et invoquée par le moteur de tour
  • Vérifications d’accès aux appels d’outils : crates/zeroclaw-runtime/src/security/ (iam_policy.rs evaluate_tool_access)
  • Orchestration des canaux : crates/zeroclaw-channels/src/orchestrator/
  • Streaming du fournisseur : crates/zeroclaw-api/src/model_provider.rs (énumération StreamEvent, réexportée depuis zeroclaw-providers), compatible.rs (analyseur SSE)

Depuis #7415, chaque transport (channels, CLI, cron, gateway WebSocket, RPC/zerocode, ACP et l’API Agent intégrée) exécute le même moteur de tour : run_tool_call_loop dans crates/zeroclaw-runtime/src/agent/turn/. Les points d’entrée de streaming et intégrés sont de fins wrappers dans agent.rs qui définissent des paramètres propres à chaque appelant (déduplication, comportement du plafond d’itérations, émission d’événements) autour de la boucle partagée. Le module turn/ comporte un fichier par étape :

Fichier(s)Étape
mod.rsorchestrateur : contrôle d’itération, paramètres, vidage de pilotage
history_window.rs · tool_specs.rs · vision_route.rspré-appel : maintenance de l’historique, spécifications des outils, routage de la vision
provider_call.rs · stream_consume.rs · stream_guard.rsl’appel du LLM, la consommation du flux, la protection du protocole en cours de flux
parse_response.rs · protocol_detect.rs · context_recovery.rsinterprétation des réponses, détection des problèmes d’analyse, récupération après dépassement
approval_gate.rs · call_prep.rsapprobation et préparation des appels d’outils (déduplication, hooks, valeurs par défaut de livraison)
post_exec.rs · results_collect.rs · history_append.rs · max_iter.rsenregistrement des résultats, détection de boucle, ajout à l’historique, plafond d’itérations
context.rs · events.rs · knobs.rs · steering.rs · outcome.rs · redact.rs · delivery_defaults.rstypes partagés : contexte de tour, événements, paramètres par appelant, pilotage, résultats, nettoyage des identifiants