Flux d'événements de session
Envoyez des événements, diffusez les réponses en streaming, et interrompez ou redirigez votre session en cours d'exécution.
La communication avec Claude Managed Agents est basée sur les événements. Vous envoyez des événements utilisateur à l'agent, et vous recevez en retour des événements d'agent et de session pour suivre l'état.
Types d'événements
Les événements circulent dans deux directions.
- Les événements utilisateur et les événements système sont ceux que vous envoyez à l'agent : les événements
user.*démarrent une session et l'orientent au fur et à mesure de sa progression ;system.messageajoute un contexte de niveau système qui s'applique au tour qui l'accompagne et à tous les tours suivants. - Les événements de session, les événements de span et les événements d'agent vous sont envoyés pour vous offrir une observabilité sur l'état de votre session et la progression de l'agent. Les connexions de flux qui y souscrivent reçoivent également des deltas d'événements.
Les chaînes de type des événements de session, de span, d'agent, utilisateur et système suivent une convention de nommage {domain}.{action}. Les événements d'aperçu delta réservés au flux (event_start, event_delta) constituent l'exception. Consultez Types d'événements dans la référence pour le catalogue complet. Les types d'événements webhook sont distincts, et certains de leurs noms diffèrent de ceux du flux (par exemple, session.status_idled plutôt que session.status_idle).
Chaque événement persisté inclut un horodatage processed_at défini lorsque le traitement de l'événement se termine. Sur les événements que vous envoyez, processed_at est null tant que l'événement est encore en file d'attente derrière des événements antérieurs. Les exceptions sont user.define_outcome, user.custom_tool_result et user.tool_result, qui sont traités dès réception et renvoyés en écho avec processed_at déjà renseigné.
Intégration des événements
Envoyez un événement user.message pour démarrer ou poursuivre le travail de l'agent :
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [
{
"type": "text",
"text": "Analyze the performance of the sort function in utils.py",
},
],
},
],
)Envoyez un événement user.interrupt pour arrêter l'agent en cours d'exécution, puis enchaînez avec un événement user.message pour le rediriger :
# Agent is currently analyzing a file...
# Interrupt with a new direction:
client.beta.sessions.events.send(
session.id,
events=[
{"type": "user.interrupt"},
{
"type": "user.message",
"content": [
{
"type": "text",
"text": "Instead, focus on fixing the bug in line 42.",
},
],
},
],
)L'appel retourne dès que les événements sont mis en file d'attente, et le processed_at de l'interruption reste null jusqu'à ce que l'agent l'applique. Une réponse du modèle en cours s'arrête immédiatement. L'interruption peut prendre plus de temps à s'appliquer pendant que des appels d'outils sont en cours d'exécution, et la session reste running jusqu'à ce qu'elle le soit. L'événement user.interrupt apparaît ensuite sur le flux, et le tour interrompu se termine par un événement session.status_idle. Son stop_reason est end_turn, la même valeur que pour un tour qui se termine de lui-même ; il n'existe pas de raison d'arrêt spécifique à l'interruption. L'agent commence son tour suivant avec le user.message que vous avez envoyé après l'interruption.
Recevez en streaming les événements de la session pour obtenir des mises à jour en temps réel pendant que l'agent travaille. Seuls les événements émis après l'ouverture du flux sont délivrés ; ouvrez donc le flux avant d'envoyer des événements afin d'éviter une condition de course.
# Open the stream first, then send the user message
with client.beta.sessions.events.stream(session.id) as stream:
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [{"type": "text", "text": "Summarize the repo README"}],
},
],
)
for event in stream:
match event.type:
case "agent.message":
for block in event.content:
if block.type == "text":
print(block.text, end="")
case "session.status_idle":
break
case "session.error":
error_message = event.error.message if event.error else "unknown"
print(f"\n[Error: {error_message}]")
breakPour vous reconnecter à une session existante sans manquer d'événements :
- Ouvrez un nouveau flux.
- Listez l'historique complet des événements pour initialiser un ensemble d'identifiants d'événements déjà vus.
- Suivez le flux en direct, en ignorant tout événement déjà renvoyé par la liste de l'historique.
with client.beta.sessions.events.stream(session.id) as stream:
# Stream is open and buffering. List history before tailing live.
history = client.beta.sessions.events.list(session.id)
seen_event_ids = {past_event.id for past_event in history}
# Tail live events, skipping anything already seen
for event in stream:
if event.type == "event_start" or event.type == "event_delta":
# Delta previews aren't enabled on this connection.
continue
if event.id in seen_event_ids:
continue
seen_event_ids.add(event.id)
match event.type:
case "agent.message":
for block in event.content:
if block.type == "text":
print(block.text, end="")
case "session.status_idle":
breakRécupérez l'historique complet des événements d'une session :
events = client.beta.sessions.events.list(session.id)
for event in events.data:
print(f"[{event.type}] {event.processed_at}")Passez un filtre types pour ne renvoyer que des types d'événements spécifiques :
events = client.beta.sessions.events.list(
session.id,
types=["agent.tool_use", "agent.tool_result"],
)
for event in events.data:
print(f"[{event.type}] {event.processed_at}")Deltas d'événements
Par défaut, le texte de réponse de l'agent atteint le flux sous forme d'événements agent.message mis en mémoire tampon, chacun n'étant é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. Un aperçu n'est pas la réponse : les aperçus sont une aide à l'affichage fournie au mieux, et l'agent.message mis en mémoire tampon constitue toujours l'enregistrement faisant autorité. Un client qui ignore les aperçus reçoit tout de même un flux complet et correct.
Souscrire aux aperçus
Les aperçus sont activés sur demande, par connexion de flux. Ajoutez le paramètre de requête event_deltas[] au flux que vous lisez, en le répétant une fois pour chaque type d'événement dont vous souhaitez un aperçu. Comme [] est un motif glob du shell, 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. Les deux points de terminaison de flux acceptent le paramètre : le flux au niveau de la session à GET /v1/sessions/{session_id}/events/stream, et le flux propre à chaque thread de session à GET /v1/sessions/{session_id}/threads/{thread_id}/stream. Les valeurs acceptées sont agent.message et agent.thinking ; toute autre valeur renvoie une erreur 400, de même qu'une requête comportant plus de 100 valeurs. Les aperçus d'un sous-agent apparaissent sur le flux de thread propre à ce sous-agent.
Lorsqu'un événement faisant l'objet d'un aperçu 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"
}
}
}Lorsqu'un événement agent.thinking fait l'objet d'un aperçu, seul l'event_start est émis. Aucun événement event_delta ne suit, et l'événement agent.thinking mis en mémoire tampon qui conclut l'aperçu ne porte aucun contenu de réflexion ; il s'agit d'un signal de progression, et non d'un porteur de contenu.
Contrairement aux événements persistés, event_start et event_delta n'ont ni id ni processed_at propres. Le seul identifiant qu'ils portent est l'id de l'événement dont ils donnent un aperçu.
Accumuler et réconcilier
Chaque SDK prenant en charge les deltas d'événements inclut un utilitaire d'accumulation qui gère pour vous la tenue des index. Les utilitaires Go, Java, Ruby et C# indexent également l'aperçu en cours d'accumulation par l'id de l'événement ; avec les utilitaires Python, TypeScript et PHP, vous tenez vous-même cette table de correspondance et intégrez chaque delta dans l'entrée correspondant à son id. Le modèle manuel fonctionne également dans tous les langages lorsque vous avez besoin d'une tenue personnalisée : appliquez-le aux types d'événements générés.
Dans le modèle manuel, traitez l'aperçu comme un tampon de travail et l'événement mis en mémoire tampon comme l'enregistrement de référence. Indexez le tampon par (event_id, index). Réconciliez par requête au modèle : un tour s'ouvre avec un unique événement session.status_running, puis, sur un tour qui se termine normalement, chaque requête au modèle produit, dans l'ordre, span.model_request_start, event_start, les événements event_delta, l'agent.message mis en mémoire tampon, et enfin span.model_request_end (dans l'onglet Événements de span). Sur le fil, voici la portion en aperçu 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 :
- Sur
event_start, notez l'idannoncé. Les identifiants concordent toujours :event_start.event.id, chaqueevent_delta.event_idet l'idde l'agent.messagemis en mémoire tampon ont la même valeur. - Sur chaque
event_delta, ajoutezdelta.content.textà l'entrée située à(event_id, delta.index)et affichez le texte en cours. Le premier delta pour unindexcrée cette entrée. - Lorsque l'
agent.messagemis en mémoire tampon arrive, faites-le correspondre parid, supprimez l'aperçu accumulé et affichez le contenu du message à la place. - 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. Plus aucun delta n'arrivera pour lui. Si le tour échoue ou est interrompu, l'événement mis en mémoire tampon peut ne jamais arriver ;span.model_request_end, lui, arrive toujours.
Garanties sur lesquelles repose le modèle :
- 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 decontent[index].textdans l'événement mis en mémoire tampon (un préfixe, pas nécessairement le texte entier, car des deltas peuvent être abandonnés sous charge). - Une connexion émet au plus un
event_startparevent_id, et l'événement mis en mémoire tampon est la dernière chose que cette connexion délivre pour cetid.
# Preview snapshots, keyed by event id. accumulate_managed_agents_event folds each
# event_start / event_delta into an agent.message snapshot; the buffered
# agent.message replaces it.
previews: dict[str, BetaManagedAgentsAgentMessageEvent] = {}
# Opt in to agent.message previews on this connection
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":
# The buffered event is the record: it replaces and closes the preview
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":
# No more deltas are coming. Close any preview whose
# buffered event never arrived.
for event_id in previews:
print(f"span.model_request_end closing preview for {event_id}")
previews.clear()
case "session.status_idle":
breakAperçu des événements de thread de session
Dans une session multi-agents, chaque thread de session possède son propre flux d'événements à GET /v1/sessions/{session_id}/threads/{thread_id}/stream, et il accepte le même paramètre event_deltas[] avec les mêmes valeurs. Les aperçus sont limités au thread par conception : une connexion ne donne un aperçu que du thread qu'elle lit. Les aperçus d'un thread enfant sont délivrés sur le flux propre à cet enfant et ne sont jamais republiés sur le flux au niveau de la session, dont les aperçus restent limités au thread principal. Pour observer le texte d'un sous-agent au fur et à mesure que le modèle le génère, ouvrez le flux de thread de ce sous-agent.
Il est facile de se tromper sur le chemin du flux de thread : il s'agit de /threads/{thread_id}/stream, et non de /events/stream (qui n'existe qu'au niveau de la session), et il n'existe pas de point de terminaison /threads/{thread_id}/events/stream.
Les événements d'aperçu eux-mêmes ne changent pas. event_start et event_delta ont la même forme sur un flux de thread que sur le flux au niveau de la session, et le modèle accumuler et réconcilier s'applique tel qu'il est décrit. Le seul ajustement concerne la tenue : exécutez une instance d'accumulateur par connexion de flux.
# List the session's threads and pick a child: child threads carry a non-null
# parent_thread_id, and the primary thread's parent_thread_id is null.
child_thread = next(
thread
for thread in client.beta.sessions.threads.list(session.id)
if thread.parent_thread_id is not None
)
# The child thread's stream takes the same event_deltas parameter as the
# session stream.
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":
# The buffered event is the authoritative record; render its content
print()
for block in event.content:
if block.type == "text":
print(block.text, end="")
print()
case "session.thread_status_idle":
breakLa boucle de lecture se termine sur session.thread_status_idle, l'événement émis lorsque le tour du thread de session se termine et que le thread devient inactif.
Limitations
Les aperçus sont optimisés pour la réactivité. Développez en tenant compte de ces contraintes :
- Au mieux : sous charge, le serveur peut abandonner des deltas pour un événement. Lorsque c'est le cas, vous recevez un préfixe contigu du texte, puis plus aucun delta pour cet événement. L'
agent.messagemis en mémoire tampon arrive tout de même complet. Ne traitez jamais un aperçu accumulé comme définitif. - Pas de relecture à la reconnexion : les deltas ne sont délivrés qu'à la connexion qui y a souscrit, tant qu'elle est ouverte. Cela s'applique aussi bien au flux au niveau de la session qu'à chaque flux de thread de session, et 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. Si le flux est coupé, suivez la procédure de reconnexion de l'onglet Streaming des événements : rouvrez le flux et listez l'historique des événements. L'historique inclut tous les événements mis en mémoire tampon émis pendant que vous étiez déconnecté, y compris l'
agent.messageque votre aperçu attendait. Il n'existe aucun moyen de redemander les deltas manqués. - Un seul thread, texte uniquement : les aperçus couvrent le texte de l'assistant sur le thread que la connexion lit. L'utilisation d'outils, les résultats d'outils, les résultats MCP et l'activité sur tout autre thread de session ne font jamais l'objet d'un aperçu sur cette connexion.
agent.thinkinglimité au début : un aperçuagent.thinkingn'émet que l'event_startpour signaler qu'un bloc de réflexion a commencé ; aucun événementevent_deltane le suit.- Jamais persistés :
event_startetevent_deltan'existent que sur le flux en direct. Ils n'apparaissent ni dans l'historique des événements de la session (GET /v1/sessions/{session_id}/events) ni dans l'historique des événements d'aucun thread de session.
Dépanner les aperçus
Si le flux ne se comporte pas comme vous l'attendez :
| Vous observez | Ce que cela signifie |
|---|---|
Un flux avec des événements mis en mémoire tampon mais aucun event_start ni event_delta | La connexion que vous lisez n'a pas souscrit (event_deltas[] s'applique par connexion, et non par session), ou le tour n'a jamais touché le thread que vous recevez en streaming. Les aperçus sont limités au thread ; listez donc les threads de la session (GET /v1/sessions/{session_id}/threads) pour trouver celui qui s'est exécuté. |
| Une erreur 404 sur l'URL du flux | Le chemin ou un identifiant est incorrect, ou la requête ne porte aucun en-tête bêta managed-agents. Les points de terminaison de thread sont soumis à la bêta ; sans l'en-tête, ils n'existent donc pas. |
Une erreur 400 mentionnant event_deltas | Seuls agent.message et agent.thinking sont acceptés. |
Scénarios supplémentaires
Gestion des appels d'outils personnalisés
Lorsque l'agent invoque un outil personnalisé :
- La session émet un événement
agent.custom_tool_usecontenant le nom de l'outil et son entrée. - La session se met en pause avec un événement
session.status_idlecontenantstop_reason: requires_action. Les identifiants des événements bloquants se trouvent dans le tableaustop_reason.event_ids. - Exécutez l'outil dans votre système et envoyez un événement
user.custom_tool_resultpour chacun, en passant l'identifiant de l'événement dans le paramètrecustom_tool_use_idaccompagné du contenu du résultat. - Une fois tous les événements bloquants résolus, la session repasse à l'état
running.
with client.beta.sessions.events.stream(session.id) as stream:
for event in stream:
if event.type == "session.status_idle" and (stop_reason := event.stop_reason):
match stop_reason.type:
case "requires_action":
for event_id in stop_reason.event_ids:
# Look up the custom tool use event and execute it
tool_event = events_by_id[event_id]
result = call_tool(tool_event.name, tool_event.input)
# Send the result back
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.custom_tool_result",
"custom_tool_use_id": event_id,
"content": [{"type": "text", "text": result}],
},
],
)
case "end_turn":
breakConfirmation d'outil
Un appel d'outil attend votre confirmation sous une politique d'autorisation always_ask, ou sous auto lorsque le serveur ne parvient à aucune décision. Dans ce cas :
- La session émet un événement
agent.tool_useouagent.mcp_tool_use. - La session se met en pause avec un événement
session.status_idledont lestop_reason.typeestrequires_action. Les ID des événements bloquants se trouvent dans le tableaustop_reason.event_ids. - Envoyez un événement
user.tool_confirmationpour chacun, en passant l'ID de l'événement dans le paramètretool_use_id. Définissezresultsur"allow"ou"deny". Utilisezdeny_messagepour expliquer un refus. - Une fois tous les événements bloquants résolus, la session repasse à l'état
running.
Chaque événement agent.tool_use et agent.mcp_tool_use porte evaluated_permission (allow, ask ou deny), et seuls les événements dont evaluated_permission vaut "ask" attendent une confirmation. La plupart des événements portent également un objet evaluation qui indique quelle politique a produit ce résultat, décrit dans Voir comment chaque appel a été évalué. Par exemple, un appel bash mis en pause sous une politique always_ask apparaît sur le flux comme suit :
{
"type": "agent.tool_use",
"id": "sevt_01def...",
"name": "bash",
"input": {
"command": "pip install -r requirements.txt"
},
"evaluated_permission": "ask",
"evaluation": {
"type": "always_ask"
},
"processed_at": "2026-03-25T14:01:45Z"
}with client.beta.sessions.events.stream(session.id) as stream:
for event in stream:
if event.type == "session.status_idle" and (stop_reason := event.stop_reason):
match stop_reason.type:
case "requires_action":
for event_id in stop_reason.event_ids:
# Approve the pending tool call
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
},
],
)
case "end_turn":
breakReprise d'une session inactive
Les sessions persistent entre les interactions. L'historique de conversation est conservé, sauf si la session est explicitement supprimée. Lorsqu'une session devient inactive, son sandbox fait l'objet d'un point de contrôle, ce qui préserve l'état complet du sandbox, y compris le système de fichiers, les paquets installés et tous les fichiers créés par l'agent. Cela vous permet de reprendre proprement après une période d'inactivité.
Pour reprendre une session, envoyez-lui un événement user.message comme d'habitude :
# Resume a previously created session by sending it a new user.message event.
# In production, pass the stored ID of the session you want to resume.
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [
{
"type": "text",
"text": "Now run the tests against the changes you made earlier.",
},
],
},
],
)Atteinte du budget d'une session
Une session créée avec un budget se met en pause au lieu de dépasser ses dépenses. Lorsque le coût catalogue suivi de la session atteint le plafond, la plateforme met chaque thread en pause avant sa prochaine requête au modèle, et la session devient inactive avec un stop_reason de budget_reached au lieu de se terminer. La requête qui a fait passer le total au-delà du plafond s'exécute jusqu'à son terme, de sorte que le list_cost rapporté par l'instantané session.usage peut indiquer une valeur égale ou légèrement supérieure au plafond. Sur le flux, la pause arrive sous la forme de trois événements, dans l'ordre :
session.thread_status_idleavecstop_reason: budget_reached, pour chaque thread au moment où il se met en pause.session.usage, un instantané de l'utilisation cumulée de la session et du coût catalogue suivi.session.status_idleavecstop_reason: budget_reached. L'événementsession.usageprécède toujours immédiatement cet état inactif.
Un thread dont la requête finale franchit le plafond et termine en même temps son tour rapporte end_turn sur son propre événement session.thread_status_idle, tandis que la session rapporte toujours budget_reached ; basez-vous sur le stop_reason au niveau de la session pour détecter la pause.
Tant que la session est à son plafond, elle n'accepte que les événements qui règlent le travail déjà en cours : user.tool_confirmation, user.tool_result, user.custom_tool_result et user.interrupt. Tout événement qui démarrerait un nouveau travail, y compris user.message, est rejeté avec une erreur 400 mentionnant cette liste. Lorsqu'une session comporte à la fois un thread en attente d'une demande d'outil et un thread en pause au plafond, le stop_reason au niveau de la session est requires_action, et non budget_reached : régler la demande ne déclenche pas de requête au modèle, répondez-y donc comme d'habitude.
Aucun événement ne reprend une session en pause à son plafond. Mettez plutôt à jour le budget de la session : modifier le plafond pour toute valeur supérieure au coût catalogue consommé, ou supprimer le budget en mettant à jour la session avec "budget": null, reprend automatiquement le travail en pause. Consultez Budgets de session pour savoir comment le coût catalogue est suivi et connaître la sémantique complète de mise à jour du budget.
Envoi de messages système
Envoyez un événement system.message pour fournir à l'agent un contexte privilégié de niveau système qui s'applique au tour qui l'accompagne et à tous les tours suivants. Contrairement au champ system de la définition de l'agent (qui définit l'invite système de premier niveau), le contenu de system.message est ajouté au contexte système de la session sous la forme d'un tour role: "system" au lieu de remplacer cette invite. Utilisez-le lorsque l'agent a besoin de directives de niveau système mises à jour en cours de session : une persona différente, des contraintes révisées ou un contexte récupéré à l'exécution qui doit façonner le comportement du modèle par la suite.
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "system.message",
"content": [
{
"type": "text",
"text": "The user's current timezone is America/New_York.",
},
],
},
],
)Tant que la session est inactive avec stop_reason: requires_action, un system.message n'est accepté que lorsqu'il suit un événement de résultat d'outil dans la même requête ; envoyé seul ou avec un user.message, il est rejeté jusqu'à ce que les événements d'outil en attente soient résolus. content accepte de 1 à 1000 éléments de texte.
Suivi de l'utilisation
L'objet session inclut un champ usage contenant l'utilisation cumulée de la session : le nombre de tokens, l'utilisation d'outils serveur, le temps actif et le coût catalogue suivi. Récupérez la session une fois qu'elle est devenue inactive pour lire les derniers totaux.
{
"id": "sesn_01...",
"status": "idle",
"usage": {
"input_tokens": 5000,
"output_tokens": 3200,
"cache_read_input_tokens": 20000,
"cache_creation": {
"ephemeral_5m_input_tokens": 2000,
"ephemeral_1h_input_tokens": 0
},
"list_cost": {
"amount": "187",
"currency": "USD"
},
"active_seconds": 342.5,
"server_tool_use": {
"web_search_requests": 3,
"web_fetch_requests": 0
}
}
}input_tokens indique les tokens d'entrée non mis en cache et output_tokens indique le total des tokens de sortie sur l'ensemble des appels au modèle de la session. Le champ cache_read_input_tokens indique les tokens lus depuis le cache de prompts, et l'objet cache_creation détaille les tokens de création de cache par durée de vie du cache (ephemeral_5m_input_tokens et ephemeral_1h_input_tokens). Les entrées de cache utilisent par défaut un TTL de 5 minutes, de sorte que les tours consécutifs dans cette fenêtre bénéficient de lectures en cache, ce qui réduit le coût par token.
list_cost est la consommation cumulée de la session tarifée aux prix catalogue publics, sous forme d'un nombre entier de centimes dans une chaîne de caractères, accompagné d'un code de devise. active_seconds est le temps cumulé pendant lequel la session avait au moins un thread en cours d'exécution ; l'activité simultanée de threads concurrents n'est comptée qu'une seule fois, contrairement au champ active_seconds de l'objet stats de la session, qui additionne le temps actif propre à chaque thread. Ce chiffre dédupliqué est la durée sur laquelle le coût d'exécution de la session est tarifé. server_tool_use compte les requêtes d'outils exécutées côté serveur à des fins de tarification : les requêtes de recherche web sont intégrées au coût catalogue par requête, tandis que les requêtes de récupération web (web fetch) n'entraînent aucun frais par requête et ne sont pas mesurées, de sorte que web_fetch_requests affiche 0. Le champ usage propre à chaque thread de session contient également list_cost et active_seconds. Les chiffres par thread sont arrondis indépendamment et excluent le coût de temps d'exécution de la session ; leur somme ne correspond donc pas exactement au list_cost de la session. Le chiffre de la session fait autorité.
Vous n'avez pas besoin d'interroger la session pour observer ces totaux. L'événement session.usage transporte le même instantané cumulé (l'objet usage, plus le budget de la session, qui vaut null lorsque la session n'en a pas) sur le flux de la session et dans l'historique des événements. Il est émis lors des transitions vers l'état inactif plutôt que selon un minuteur : la session en émet un immédiatement avant de devenir inactive, quelle que soit la raison d'arrêt, et un lorsqu'un thread se met en pause en atteignant un budget de session. Un lecteur du flux voit ainsi le coût final d'un tour, ou du travail ayant atteint un budget, sans récupération supplémentaire.
Pour appliquer une limite de dépenses, définissez un budget de session plutôt que d'interroger l'utilisation et d'arrêter la session vous-même. La plateforme tarifie la consommation de la session en continu et met chaque thread en pause avant sa prochaine requête au modèle dès que le coût catalogue de la session atteint le plafond ; consultez Atteindre un budget de session pour voir à quoi cela ressemble sur le flux.
Observabilité dans la Console
La Claude Console inclut une visionneuse de sessions permettant d'inspecter ce qu'un agent a fait sans écrire de code. Dans la barre latérale de la Console, sous Managed Agents, sélectionnez Sessions pour voir toutes les sessions de l'espace de travail avec leur statut, leur agent, leur utilisation de tokens, leur coût et leur date de création, puis sélectionnez une session pour l'ouvrir. La visionneuse de sessions n'est accessible qu'aux développeurs et aux administrateurs. Elle affiche :
- Mini-carte chronologique : une vue d'ensemble zoomable de l'activité de la session au fil du temps, avec une piste par thread dans les sessions multi-agents. Sélectionnez une piste pour afficher ce thread, ou sélectionnez un repère pour accéder directement à son événement.
- Transcription : la conversation regroupée par requête au modèle, incluant la réflexion, les appels d'outils avec leurs entrées et résultats, et le texte des messages au fur et à mesure de leur streaming. Vous pouvez filtrer les événements et les copier ou les télécharger au format JSON.
- Inspecteur : un panneau latéral redimensionnable contenant des détails sur la session, répartis en cinq onglets :
- Session affiche les détails et métadonnées de la session, son coût cumulé au fil du temps, ainsi que les dépenses par rapport au budget de la session lorsqu'il est défini.
- Events liste chaque événement brut du thread actuel dans l'ordre où le serveur l'a envoyé ; sélectionnez un événement pour voir son JSON. Un message diffusé en streaming pendant que la page était ouverte dispose également d'une vue Deltas de ses deltas d'événements.
- Tools liste les outils avec lesquels les agents de la session sont configurés, ainsi que le nombre d'appels, les échecs et la durée médiane ; sélectionnez un outil pour voir ses appels et accéder à l'un d'eux dans la transcription.
- Resources liste les fichiers, dépôts et magasins de mémoire montés à leurs chemins dans le conteneur, y compris les mémoires de chaque magasin et les modifications que cette session y a apportées, ainsi que les fichiers que l'agent a écrits dans
/mnt/session/outputset les skills attachées aux agents de la session. - Threads liste chaque thread avec son statut, la taille de son contexte et son coût. Sélectionnez un thread pour afficher ses détails, tels que l'agent, le modèle, l'utilisation du contexte et le coût.
Ajoutez ?event={event_id} à l'URL d'une session pour ouvrir la session à un événement spécifique.
Avec ant beta:sessions connect, vous pouvez ouvrir le même visualiseur depuis la CLI ant ou suivre la session dans votre terminal. Consultez Se connecter à une session Managed Agents depuis votre terminal.
Conseils de débogage
- Vérifiez les événements de session : les erreurs de session sont transmises via l'événement
session.error. - Examinez les résultats des outils : les échecs d'exécution d'outils expliquent souvent un comportement inattendu de l'agent.
- Suivez l'utilisation des tokens : surveillez la consommation de tokens pour optimiser les prompts et réduire les coûts.
- Utilisez les invites système : ajoutez des instructions de journalisation à l'invite système pour que l'agent explique son raisonnement.
- Dépannez les aperçus : si un flux ayant activé les deltas d'événements ne se comporte pas comme prévu, consultez Dépanner les aperçus.
Was this page helpful?