Claude Platform Docs
Managed AgentsDéléguer du travail à votre agent

Prévisualiser les réponses avec les deltas d'événements

Affichez le texte de réponse de l'agent sous forme d'aperçu en direct pendant que le modèle est encore en train de le générer.

Par défaut, le texte de réponse de l'agent parvient au flux d'événements de session sous forme d'événements agent.message mis en mémoire tampon. Chacun n'est émis qu'une fois terminée la requête au modèle qui l'a produit. Les « event deltas » (deltas d'événements) vous permettent d'afficher ce texte de manière incrémentale, sous forme d'aperçu en direct, pendant que le modèle est encore en train de le générer.

Les aperçus sont une aide à l'affichage fournie au mieux, et le agent.message mis en mémoire tampon constitue toujours l'enregistrement de référence. Un client qui ignore les aperçus reçoit tout de même un flux complet et correct.

Activer les aperçus

Les aperçus s'activent par connexion de flux. Ajoutez le paramètre de requête event_deltas[] au flux que vous lisez, et répétez-le une fois pour chaque type d'événement que vous souhaitez prévisualiser. Les valeurs acceptées sont agent.message et agent.thinking. Toute autre valeur renvoie une erreur 400, tout comme une requête comportant plus de 100 valeurs.

Les deux points de terminaison de flux acceptent ce paramètre :

  • Flux au niveau de la session : GET /v1/sessions/{session_id}/events/stream
  • Flux de fil de session : GET /v1/sessions/{session_id}/threads/{thread_id}/stream

Les aperçus d'un sous-agent apparaissent sur le propre flux de fil de ce sous-agent.

[] est un motif de glob du shell, donc mettez l'URL entre guillemets chaque fois que vous construisez la requête dans un shell. Les exemples encodent les crochets en pourcentage sous la forme %5B%5D, ce qui fonctionne également.

Événements d'aperçu

Lorsqu'un événement prévisualisé commence, le flux émet un event_start portant le type et l'id de l'événement à venir :

{
  "type": "event_start",
  "event": {
    "type": "agent.message",
    "id": "sevt_01abc..."
  }
}

Pour agent.message, le début est suivi d'événements event_delta portant du texte incrémental. Chaque delta désigne l'événement qu'il prolonge dans event_id et le bloc de contenu qu'il prolonge dans delta.index :

{
  "type": "event_delta",
  "event_id": "sevt_01abc...",
  "delta": {
    "type": "content_delta",
    "index": 0,
    "content": {
      "type": "text",
      "text": "Here is the summary"
    }
  }
}

Pour agent.thinking, seul l'event_start est émis, pour signaler qu'un bloc de réflexion a commencé. Aucun événement event_delta ne suit. L'événement agent.thinking mis en mémoire tampon qui conclut l'aperçu est un signal de progression et ne contient aucun contenu de réflexion.

Contrairement aux événements persistés, event_start et event_delta n'ont pas d'id ni de processed_at propres. Le seul identifiant qu'ils portent est l'id de l'événement qu'ils prévisualisent. Leurs chaînes de type font également exception à la convention de nommage {domain}.{action} des événements persistés.

Accumuler et réconcilier

Chaque SDK qui prend en charge les deltas d'événements inclut un assistant d'accumulation qui gère pour vous la comptabilité des index. Le modèle manuel de cette section fonctionne dans tous les langages lorsque vous avez besoin d'une comptabilité personnalisée. Appliquez-le aux types d'événements générés.

Dans le modèle manuel, conservez le texte d'aperçu dans une table temporaire indexée par (event_id, index), et traitez l'événement mis en mémoire tampon comme l'enregistrement de référence. Réconciliez les deux pour chaque requête au modèle.

Un tour s'ouvre avec un seul événement session.status_running. Lors d'un tour qui se termine normalement, chaque requête au modèle produit ensuite ces événements, dans l'ordre :

  1. span.model_request_start
  2. event_start
  3. Les événements event_delta
  4. Le agent.message mis en mémoire tampon
  5. span.model_request_end (dans l'onglet Span events)

Sur le réseau, voici la partie prévisualisée de cette séquence, entrelacée avec les autres événements mis en mémoire tampon de la connexion :

event_start     {"event": {"type": "agent.message", "id": "sevt_01abc..."}}
event_delta     {"event_id": "sevt_01abc...", "delta": {"type": "content_delta", "index": 0, "content": {"type": "text", "text": "..."}}}
...
agent.message   {"id": "sevt_01abc...", "content": [...]}

La ligne event_delta se répète une fois par fragment de texte. Traitez chaque événement à son arrivée :

  1. Sur event_start, notez l'id annoncé. Les identifiants concordent toujours : event_start.event.id, chaque event_delta.event_id et l'id du agent.message mis en mémoire tampon ont la même valeur.
  2. Sur chaque event_delta, ajoutez delta.content.text à l'entrée située à (event_id, delta.index) et affichez le texte en cours. Le premier delta pour un index crée cette entrée.
  3. Lorsque le agent.message mis en mémoire tampon arrive, associez-le par id, supprimez l'aperçu accumulé et affichez plutôt le contenu du message.
  4. Sur span.model_request_end, fermez tout aperçu qui n'a pas été réconcilié par son événement mis en mémoire tampon. Aucun autre delta n'arrivera pour lui. Si le tour rencontre une erreur ou est interrompu, l'événement mis en mémoire tampon pourrait ne jamais arriver, mais span.model_request_end arrive quand même.

Ce modèle repose sur deux garanties :

  • La concaténation des deltas d'un aperçu dans leur ordre d'arrivée, indexés par (event_id, index), donne un préfixe de content[index].text dans l'événement mis en mémoire tampon. Ce n'est pas nécessairement le texte entier, car des deltas peuvent être abandonnés en cas de charge.
  • Une connexion émet au plus un event_start par event_id, et l'événement mis en mémoire tampon est le dernier élément que cette connexion délivre pour cet id.

Assistants d'accumulation des SDK

L'assistant de chaque SDK gère la comptabilité des index. Les assistants Go, Java, Ruby et C# indexent également l'aperçu en cours d'accumulation par l'id de l'événement. Avec les assistants Python, TypeScript et PHP, gérez vous-même cette table et intégrez chaque delta dans l'entrée correspondant à son id.

Les exemples suivants activent les aperçus agent.message et les réconcilient avec l'événement mis en mémoire tampon :

# Instantanés d'aperçu, indexés par id d'événement. accumulate_managed_agents_event intègre chaque
# event_start / event_delta dans un instantané agent.message ; l'agent.message
# mis en tampon le remplace.
previews: dict[str, BetaManagedAgentsAgentMessageEvent] = {}

# Activer les aperçus agent.message sur cette connexion
with client.beta.sessions.events.stream(
    session.id, event_deltas=["agent.message"]
) as stream:
    client.beta.sessions.events.send(
        session.id,
        events=[
            {
                "type": "user.message",
                "content": [{"type": "text", "text": "Describe the repo in one sentence."}],
            },
        ],
    )

    for event in stream:
        match event.type:
            case "event_start":
                snapshot = accumulate_managed_agents_event(None, event)
                if snapshot is not None:
                    previews[event.event.id] = snapshot
                print(f"event_start             {event.event.type} {event.event.id}")
            case "event_delta":
                preview = accumulate_managed_agents_event(previews.get(event.event_id), event)
                if preview is not None:
                    previews[event.event_id] = preview
                    text = "".join(block.text for block in preview.content)
                    print(f"event_delta             preview: {text!r}")
            case "agent.message":
                # L'événement mis en tampon fait foi : il remplace et clôt l'aperçu
                preview = accumulate_managed_agents_event(previews.pop(event.id, None), event)
                text = "".join(block.text for block in preview.content)
                print(f"agent.message           {event.id} {text!r}")
            case "span.model_request_end":
                # Plus aucun delta n'arrivera. Fermer tout aperçu dont
                # l'événement mis en tampon n'est jamais arrivé.
                for event_id in previews:
                    print(f"span.model_request_end  closing preview for {event_id}")
                previews.clear()
            case "session.status_idle":
                break

Prévisualiser les événements des fils de session

Dans une session multi-agents, chaque fil de session possède son propre flux d'événements. Il accepte le même paramètre event_deltas[] avec les mêmes valeurs.

Une connexion ne prévisualise que le fil qu'elle lit. Le flux au niveau de la session prévisualise le fil principal, et les aperçus d'un fil enfant n'y sont jamais republiés. Pour suivre le texte d'un sous-agent pendant que le modèle le génère, ouvrez le flux de fil de ce sous-agent.

Le chemin d'un flux de fil se termine par /threads/{thread_id}/stream. /events/stream n'existe qu'au niveau de la session, il n'y a donc pas de point de terminaison /threads/{thread_id}/events/stream.

event_start et event_delta ont la même forme sur un flux de fil que sur le flux au niveau de la session, et le modèle accumuler et réconcilier s'applique tel quel. Exécutez une instance d'accumulateur par connexion de flux.

# Lister les threads de la session et choisir un enfant : les threads enfants ont un
# parent_thread_id non nul, et le parent_thread_id du thread principal est null.
child_thread = next(
    thread
    for thread in client.beta.sessions.threads.list(session.id)
    if thread.parent_thread_id is not None
)

# Le stream du thread enfant accepte le même paramètre event_deltas que le
# stream de session.
with client.beta.sessions.threads.events.stream(
    child_thread.id,
    session_id=session.id,
    event_deltas=["agent.message"],
) as stream:
    for event in stream:
        match event.type:
            case "event_delta":
                print(event.delta.content.text, end="")
            case "agent.message":
                # L'événement mis en tampon fait foi ; afficher son contenu
                print()
                for block in event.content:
                    if block.type == "text":
                        print(block.text, end="")
                print()
            case "session.thread_status_idle":
                break

La boucle de lecture se termine sur session.thread_status_idle, l'événement émis lorsque le tour du fil de session se termine et que le fil devient inactif.

Limitations

  • Au mieux : en cas de charge, le serveur peut abandonner des deltas pour un événement. Dans ce cas, vous recevez un préfixe contigu du texte, puis plus aucun delta pour cet événement. Le agent.message mis en mémoire tampon arrive tout de même complet. Ne considérez jamais un aperçu accumulé comme définitif.
  • Pas de relecture à la reconnexion : les deltas ne sont délivrés qu'à la connexion qui les a activés, tant qu'elle est ouverte. Cela s'applique aussi bien au flux au niveau de la session qu'à chaque flux de fil de session. Une connexion ouverte après le début d'une requête au modèle ne reçoit aucun delta pour cet événement en cours. Il n'existe aucun moyen de redemander les deltas manqués.
  • Un seul fil, texte uniquement : les aperçus couvrent le texte de l'assistant sur le fil que lit la connexion. L'utilisation d'outils, les résultats d'outils et les résultats MCP ne sont jamais prévisualisés.
  • Jamais persistés : event_start et event_delta n'existent que sur le flux en direct. Ils n'apparaissent pas dans l'historique des événements de la session (GET /v1/sessions/{session_id}/events) ni dans l'historique des événements d'aucun fil de session.

Dépanner les aperçus

Ce que vous voyezCe que cela signifie
Un flux avec des événements mis en mémoire tampon mais sans event_start ni event_deltaLa connexion que vous lisez n'a pas activé les aperçus, ou le tour n'a jamais concerné le fil que vous diffusez. event_deltas[] s'applique par connexion, et non par session. Pour savoir quel fil s'est exécuté, listez les fils de la session (GET /v1/sessions/{session_id}/threads).
Un flux qui s'interrompt pendant un aperçuLes deltas ne sont pas rejoués. Suivez la procédure de reconnexion : rouvrez le flux et listez l'historique des événements. L'historique inclut tous les événements mis en mémoire tampon émis pendant votre déconnexion, y compris le agent.message qu'attendait votre aperçu.
Une erreur 404 sur l'URL du fluxLe chemin ou un identifiant est incorrect, ou la requête ne comporte aucun en-tête bêta managed-agents. Les points de terminaison de fil sont soumis à la bêta, donc sans l'en-tête ils n'existent pas.
Une erreur 400 mentionnant event_deltasSeuls agent.message et agent.thinking sont acceptés.

Étapes suivantes

Envoyez des événements, diffusez des réponses en streaming, et interrompez ou redirigez votre session en cours d'exécution.

Coordonnez plusieurs agents au sein d'une même session.

Was this page helpful?