Fils de session
Listez, interrompez et archivez les fils d'une session multi-agents, lisez leurs événements et gérez les autorisations d'outils entre eux.
Dans une session multi-agents, chaque agent travaille dans son propre « session thread » (fil de session). Cette page explique comment lister, interrompre et archiver les fils, les événements qu'ils envoient et le fonctionnement des autorisations d'outils entre eux. Une exécution de workflow crée également des fils de session.
Fil principal et fils de session
Le « session-level event stream » (flux d'événements au niveau de la session), à l'adresse /v1/sessions/{session_id}/events/stream, est considéré comme le « primary thread » (fil principal), qui contient une vue condensée de toute l'activité de tous les fils. Vous ne voyez pas l'activité complète des sous-agents, mais vous voyez le début et la fin de leur travail, ainsi que les événements bloquants tels que les demandes d'autorisation d'outils.
Les fils de session sont l'endroit où vous examinez en détail l'activité d'un agent spécifique.
Le status de la session est une agrégation de toute l'activité des agents ; si au moins un fil est running, alors le statut global de la session est également running. Une exécution de workflow en cours peut également maintenir la session à running, même lorsqu'aucun de ses fils ne travaille. Lorsqu'aucun fil ne travaille et qu'un fil attend votre client, la session est idle ; consultez Savoir quand le travail est terminé.
Un budget de session est un plafond unique partagé entre tous les fils d'une session. Lorsque le plafond est atteint, les fils se mettent en pause indépendamment, et le coût de chaque fil est calculé selon le modèle servi propre à ce fil.
Lister les fils
Listez tous les fils associés à une session comme suit :
for thread in client.beta.sessions.threads.list(session.id):
agent = thread.agent
label = agent.type if agent.type == "advisor" else agent.name
print(f"[{label}] {thread.status}")La liste complète inclut le fil principal. parent_thread_id vaut null pour le fil principal. Tous les autres fils sont des fils enfants. workflow_run_id vaut null sauf sur les fils d'une exécution.
Pour lister uniquement les fils ayant certains statuts, ajoutez statuses[] à la requête, et répétez-le pour indiquer plusieurs statuts, comme dans ?statuses[]=running&statuses[]=idle. Omettez-le pour renvoyer les fils de tous les statuts.
Interrompre un fil de session
Envoyez user.interrupt avec session_thread_id pour arrêter un fil spécifique. Omettre session_thread_id interrompt tous les fils non archivés de la session, y compris le fil principal. Dans une session avec des workflows dynamiques, une interruption ne met fin à aucune exécution, et une interruption qui désigne un fil d'exécution n'arrête rien. Une interruption ferme les appels d'outils en attente des autres fils enfants, mais ne comptez pas sur elle pour fermer ceux d'un fil d'exécution. Consultez Interrompre une session avec des exécutions ouvertes.
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
)Sur le fil d'un sous-agent bloqué sur requires_action, l'interruption ferme chaque appel d'outil en attente avec un résultat d'outil en erreur (« Tool execution was interrupted before completion. Please retry. ») et réémet directement session.thread_status_idle avec stop_reason: end_turn ; le modèle n'est pas échantillonné. Sur un fil enfant inactif avec end_turn ou budget_reached, l'interruption n'a aucun effet. Une interruption qui désigne un fil terminé renvoie une erreur 400. Un enfant interrompu n'envoie pas à l'agent du fil principal le rapport qu'il envoie à la fin d'un tour. Tant que cet agent attend l'enfant, il ne commence pas un autre tour avant que quelque chose d'autre ne lui parvienne, comme un user.message ou le rapport d'un autre fil.
Archiver un fil de session
Vous pouvez éventuellement archiver un fil de session lorsqu'il a terminé son travail. L'archivage d'un fil libère sa place dans la limite de 25 fils enfants. Le serveur archive lui-même les fils d'une exécution de workflow. Vous n'avez pas besoin de les archiver, et vous ne pouvez pas le faire tant que l'exécution est ouverte.
archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
print(archived.status, archived.archived_at)L'archivage ne réussit que si le fil est idle. Un fil en attente sur requires_action est considéré comme inactif et peut être archivé directement ; seul un fil en cours d'exécution doit d'abord être interrompu :
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
)
archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
print(archived.status, archived.archived_at)Événements du fil principal
Ces événements font apparaître l'activité multi-agents sur le fil principal à /v1/sessions/{session_id}/events/stream. Les événements liés aux messages sont nommés du point de vue du fil sur le flux duquel ils apparaissent : agent.thread_message_received signifie qu'un message est arrivé sur ce fil depuis un autre fil, et agent.thread_message_sent signifie que ce fil en a envoyé un. La tâche que l'agent du fil principal délègue, par exemple, arrive sur le flux du fil enfant sous la forme d'un événement agent.thread_message_received.
| Type | Description |
|---|---|
session.thread_created | Un fil a été créé. Inclut session_thread_id et agent_name. |
session.thread_status_running | Un fil a commencé une activité. |
session.thread_status_idle | L'agent associé au fil attend une entrée. Inclut un stop_reason indiquant pourquoi l'agent s'est arrêté. |
session.thread_status_terminated | Un fil s'est terminé et n'accepte plus d'entrée, par exemple parce qu'il a été archivé ou a rencontré une erreur irrécupérable. Un fil du conseiller se termine également lorsque sa consultation prend fin. |
agent.thread_message_received | Sur le fil principal, un sous-agent a envoyé un rapport ou une question à l'agent du fil principal. Inclut from_session_thread_id, from_agent_name et content. |
agent.thread_message_sent | Sur le fil principal, l'agent du fil principal a envoyé une tâche ou un message de suivi à un sous-agent. Inclut to_session_thread_id, to_agent_name et content. |
Les consultations du conseiller émettent ces mêmes événements de fil sous le nom réservé anthropic.advisor (en tant que agent_name sur les événements de cycle de vie du fil et from_agent_name sur la remise du conseil) ; consultez Donner un conseiller à la session pour la séquence.
Les fils d'une exécution de workflow apparaissent sur le flux principal comme suit :
- Événements de cycle de vie : Chaque fil d'exécution envoie
session.thread_created, avec leworkflow_run_idde l'exécution, ainsi que ses événementssession.thread_status_running,session.thread_status_idleetsession.thread_status_terminated. - Événements de message : Le prompt d'un fil d'exécution, un événement
agent.thread_message_received, reste sur son propre flux. - Événements d'exécution : Les événements
workflow_run.*arrivent également sur ce flux ; consultez Événements d'exécution. - Appels d'outils qui vous attendent : Les appels d'outils d'un fil d'exécution qui nécessitent votre client sont republiés sur ce flux, comme pour tout fil enfant. Consultez Autorisations d'outils et outils personnalisés.
Événements des fils de session
Les événements critiques sont relayés vers le fil principal. Cependant, vous pourriez tout de même vouloir examiner le raisonnement et les appels d'outils d'un agent spécifique. Pour ce faire, diffusez en streaming ou listez les événements du fil de session associé.
Chaque fil de session possède son propre flux d'événements à /v1/sessions/{session_id}/threads/{thread_id}/stream, et il accepte le même paramètre event_deltas[] que le flux au niveau de la session, ce qui vous permet de prévisualiser le texte d'un sous-agent au fur et à mesure que le modèle le génère. Une connexion ne prévisualise que le fil qu'elle lit : les aperçus d'un fil enfant n'apparaissent jamais sur le flux au niveau de la session ; pour suivre un sous-agent en direct, ouvrez donc son propre flux de fil. Consultez Prévisualiser les événements des fils de session pour l'activation, l'accumulation et la réconciliation des aperçus.
Dans une exécution de workflow, le serveur exécute un workflow : un programme que l'agent du fil principal écrit. Sur chacun des fils de l'exécution, le premier agent.thread_message_received est le prompt que le workflow a écrit. Son from_session_thread_id est l'ID du fil principal, et il n'a pas de from_agent_name. L'API ne garantit pas le texte du prompt ; ne l'analysez donc pas. L'événement session.thread_status_terminated du fil, sur le flux du fil principal, vous indique que le fil a terminé. Aucun événement n'enregistre le résultat qu'il a renvoyé au workflow.
Le flux d'un fil ne rejoue pas les événements antérieurs. Juste après session.thread_created, la liste des événements d'un fil d'exécution peut être vide, car le serveur écrit le premier événement du fil après celui-ci. Ouvrez donc d'abord le flux du fil, puis listez les événements du fil, et ignorez chaque événement diffusé dont l'id a été renvoyé par la liste.
with client.beta.sessions.threads.events.stream(
thread.id,
session_id=session.id,
) as stream:
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.thread_status_idle":
breakListez tous les événements passés d'un fil de session pour récupérer un historique complet.
for event in client.beta.sessions.threads.events.list(
thread.id,
session_id=session.id,
):
print(f"[{event.type}] {event.processed_at}")Autorisations d'outils et outils personnalisés
Si un sous-agent a besoin de quelque chose de la part de votre client, comme l'autorisation d'exécuter un appel d'outil ou le résultat d'un outil personnalisé, l'événement est republié sur le fil principal avec session_thread_id identifiant le fil de session d'origine. Un appel d'outil nécessite votre autorisation sous always_ask, ou sous auto lorsque le serveur ne parvient à aucune décision.
{
"type": "session.thread_status_idle",
"id": "sevt_01ABC...",
"session_thread_id": "sthr_01DEF...",
"agent_name": "code-reviewer",
"stop_reason": {
"type": "requires_action",
"event_ids": ["sevt_01XYZ..."]
}
}Publiez user.tool_confirmation (avec tool_use_id) ou user.custom_tool_result (avec custom_tool_use_id) ; le serveur achemine automatiquement la réponse vers le bon fil. La réponse peut apparaître sur le fil principal et sur le fil du sous-agent avec des valeurs d'id différentes. Pour faire correspondre les deux copies, comparez type et tool_use_id (ou custom_tool_use_id), et non id.
La session ne passe à idle que lorsqu'aucun fil n'est running ; session.status_idle peut donc arriver longtemps après l'appel d'un sous-agent. Vous n'avez pas à l'attendre : envoyez le user.custom_tool_result dès que l'événement agent.custom_tool_use republié arrive.
Sous auto, vos événements user.message peuvent amener le serveur à autoriser un appel qu'il refuserait autrement. Rien dans le fil d'un sous-agent ne compte comme votre intention. Votre client n'y publie aucun message, et les messages que l'agent du fil principal envoie au sous-agent ne comptent pas. Lorsque le serveur refuse un appel sous auto, rien n'est republié : l'événement et le résultat d'outil en erreur n'apparaissent que sur le flux du fil du sous-agent, et le sous-agent continue de s'exécuter.
L'exemple suivant s'insère dans la boucle d'événements du gestionnaire de confirmation d'outils. Pour chaque ID dans stop_reason.event_ids, il envoie un user.tool_confirmation qui autorise l'appel. Le même schéma s'applique à user.custom_tool_result.
for event_id in stop.event_ids:
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
}
],
)Le schéma précédent répond aux appels qu'un événement d'inactivité liste. Sur le flux principal, l'événement session.thread_status_idle d'un sous-agent peut arriver avant les événements agent.tool_use ou agent.mcp_tool_use que liste son stop_reason.event_ids. Un user.tool_confirmation pour un appel dont l'événement n'est pas encore arrivé peut renvoyer une erreur 400. Pour éviter cela, répondez à chaque appel dont l'evaluated_permission vaut ask lorsque son propre événement arrive sur le flux principal.
Was this page helpful?