La comunicación con Claude Managed Agents se basa en eventos. Envías eventos de usuario al agente y recibes eventos de agente y de sesión para hacer seguimiento del estado.
Todas las solicitudes a la Managed Agents API requieren el encabezado beta managed-agents-2026-04-01. El SDK establece el encabezado beta automáticamente.
Los eventos fluyen en dos direcciones.
user.* inician una sesión y la dirigen a medida que avanza; system.message actualiza la indicación del sistema del agente entre turnos.Las cadenas de tipo de evento de sesión, span, agente, usuario y sistema siguen la convención de nomenclatura {domain}.{action}. Los eventos de vista previa de deltas exclusivos del stream (event_start, event_delta) son la excepción. Consulta Tipos de eventos en la referencia para ver el catálogo completo.
Cada evento persistido incluye una marca de tiempo processed_at que indica cuándo se registró el evento en el servidor. Si processed_at es null, significa que el evento ha sido puesto en cola por el harness y se procesa después de que los eventos anteriores terminen de procesarse.
De forma predeterminada, el texto de respuesta del agente llega al stream como eventos agent.message almacenados en búfer, cada uno emitido solo después de que finaliza la solicitud al modelo que lo produjo. Los deltas de eventos te permiten renderizar ese texto de forma incremental, como una vista previa en vivo, mientras el modelo todavía lo está generando. Una vista previa no es la respuesta: las vistas previas son una ayuda visual de mejor esfuerzo, y el agent.message almacenado en búfer es siempre el registro autoritativo. Un cliente que ignora las vistas previas sigue recibiendo un stream completo y correcto.
Las vistas previas se habilitan por conexión de stream. Agrega el parámetro de consulta event_deltas[] a GET /v1/sessions/{session_id}/events/stream, repitiéndolo una vez por cada tipo de evento del que quieras vista previa. Los valores aceptados son agent.message y agent.thinking; cualquier otro valor devuelve un error 400. Solo el stream de eventos a nivel de sesión admite este parámetro. Los streams de eventos de hilos de sesión lo rechazan.
Cuando comienza un evento con vista previa, el stream emite un event_start que contiene el tipo y el id del evento próximo:
{
"type": "event_start",
"event": {
"type": "agent.message",
"id": "sevt_01abc..."
}
}Para agent.message, el inicio va seguido de eventos event_delta que contienen texto incremental. Cada delta indica el evento que extiende en event_id y el bloque de contenido que extiende en delta.index:
{
"type": "event_delta",
"event_id": "sevt_01abc...",
"delta": {
"type": "content_delta",
"index": 0,
"content": {
"type": "text",
"text": "Here is the summary"
}
}
}Cuando se genera la vista previa de un evento agent.thinking, solo se emite el event_start. No le siguen eventos event_delta, y el contenido llega en el evento agent.thinking almacenado en búfer como de costumbre.
A diferencia de los eventos persistidos, event_start y event_delta no tienen id ni processed_at propios. El único identificador que llevan es el id del evento del que son vista previa.
Los deltas de eventos usan un formato de transmisión diferente al de Streaming de mensajes, y la diferencia es intencional. Un agent.message con vista previa recibe un único event_start seguido solo de eventos event_delta. No hay eventos de inicio o fin por bloque de contenido ni evento de fin para el evento con vista previa en sí. El tipo de delta es content_delta, no content_block_delta. El código de acumulador escrito para la API de Messages no se puede reutilizar sin cambios.
Los SDKs de Python, TypeScript y Go incluyen un helper acumulador que indexa la vista previa por el id del evento y gestiona la contabilidad del index por ti. El patrón manual funciona en todos los lenguajes: en los demás SDKs, aplícalo a los tipos de eventos generados.
En el patrón manual, trata la vista previa como un búfer temporal y el evento almacenado en búfer como el registro. Indexa el búfer por (event_id, index). Reconcilia por solicitud al modelo: un turno se abre con un único evento session.status_running, y luego, en un turno que se completa normalmente, cada solicitud al modelo produce, en orden, span.model_request_start, event_start, los eventos event_delta, el agent.message almacenado en búfer y finalmente span.model_request_end (en la pestaña de eventos de Span). Procesa cada evento a medida que llega:
event_start, toma nota del id anunciado. Los identificadores siempre coinciden: event_start.event.id, cada event_delta.event_id y el id del agent.message almacenado en búfer son el mismo valor.event_delta, agrega delta.content.text a la entrada en (event_id, delta.index) y renderiza el texto acumulado. El primer delta para un index crea esa entrada.agent.message almacenado en búfer, emparéjalo por id, descarta la vista previa acumulada y renderiza el contenido del mensaje en su lugar.span.model_request_end, cierra cualquier vista previa que no haya sido reconciliada por su evento almacenado en búfer. No llegarán más deltas para ella. Si el turno genera un error o se interrumpe, es posible que el evento almacenado en búfer nunca llegue; span.model_request_end sí llega de todos modos.# Snapshots de vista previa, indexados por id de evento. accumulate_managed_agents_event integra cada
# event_start / event_delta en un snapshot de agent.message; el agent.message
# almacenado en búfer lo reemplaza.
previews: dict[str, BetaManagedAgentsAgentMessageEvent] = {}
# Habilita las vistas previas de agent.message en esta conexión
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":
# El evento en búfer es el registro: reemplaza y cierra la vista previa
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 llegarán más deltas. Cierra cualquier vista previa cuyo
# evento en búfer nunca llegó.
for event_id in previews:
print(f"span.model_request_end closing preview for {event_id}")
previews.clear()
case "session.status_idle":
breakLas vistas previas están optimizadas para la capacidad de respuesta. Desarrolla teniendo en cuenta estas restricciones:
agent.message almacenado en búfer sigue llegando completo. Nunca trates una vista previa acumulada como definitiva.agent.message que tu vista previa estaba esperando. No hay forma de volver a solicitar deltas perdidos.agent.thinking solo de inicio: Una vista previa de agent.thinking emite solo el event_start como señal de que ha comenzado un bloque de pensamiento; no le siguen eventos event_delta.event_start y event_delta existen solo en el stream en vivo. No aparecen en el historial de eventos de la sesión (GET /v1/sessions/{session_id}/events).Cuando el agente invoca una herramienta personalizada:
agent.custom_tool_use que contiene el nombre de la herramienta y la entrada.session.status_idle que contiene stop_reason: requires_action. Los IDs de los eventos bloqueantes están en el arreglo stop_reason.event_ids.user.custom_tool_result por cada uno, pasando el ID del evento en el parámetro custom_tool_use_id junto con el contenido del resultado.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:
# Busca el evento de uso de herramienta personalizada y ejecútalo
tool_event = events_by_id[event_id]
result = call_tool(tool_event.name, tool_event.input)
# Envía el resultado de vuelta
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":
breakCuando una política de permisos requiere confirmación antes de que se ejecute una herramienta:
agent.tool_use o agent.mcp_tool_use.session.status_idle que contiene stop_reason: requires_action. Los IDs de los eventos bloqueantes están en el arreglo stop_reason.event_ids.user.tool_confirmation por cada uno, pasando el ID del evento en el parámetro tool_use_id. Establece result en "allow" o "deny". Usa deny_message para explicar una denegación.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:
# Aprueba la llamada a herramienta pendiente
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
},
],
)
case "end_turn":
breakLas sesiones persisten entre interacciones. El historial de conversación se conserva a menos que la sesión se elimine explícitamente. Cuando una sesión queda inactiva, se crea un checkpoint de su sandbox, preservando el estado completo del sandbox, incluido el sistema de archivos, los paquetes instalados y cualquier archivo que el agente haya creado. Esto te permite reanudar limpiamente después de un periodo de inactividad.
Aunque el historial de la sesión se persiste hasta que se elimina, los checkpoints solo se conservan durante 30 días después de la última actividad de la sesión. Si tu flujo de trabajo requiere que el estado completo del sandbox (archivos, herramientas instaladas, etc.) persista más allá de 30 días, envía eventos user.message periódicos para reiniciar el temporizador de inactividad antes de que el checkpoint expire.
Para reanudar una sesión, envíale un evento user.message como de costumbre:
# En producción, pasa el ID almacenado de la sesión que quieres reanudar.
ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
events:
- type: user.message
content:
- type: text
text: Now run the tests against the changes you made earlier.
YAMLsystem.message actualmente solo es compatible con Claude Opus 4.8. Si algún modelo configurado en el agente no admite la inyección de sistema en mitad de la conversación, el evento se rechaza con un error de validación model_does_not_support_mid_conversation_system.
Envía un evento system.message para actualizar la indicación del sistema del agente entre turnos. A diferencia del campo system en la definición del agente (que se fija al crear la sesión), system.message te permite cambiar la indicación del sistema a medida que avanza la sesión. Úsalo cuando el agente necesite orientación actualizada a nivel de sistema en mitad de la sesión: una persona diferente, restricciones revisadas o contexto obtenido en tiempo de ejecución que deba moldear el comportamiento del modelo de ahí en adelante.
ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
events:
- type: system.message
content:
- type: text
text: "The user's current timezone is America/New_York."
YAMLsystem.message no se puede enviar mientras la sesión está inactiva con stop_reason: requires_action. content acepta de 1 a 1000 elementos de texto.
El objeto de sesión incluye un campo usage con estadísticas acumuladas de tokens. Obtén la sesión después de que quede inactiva para leer los totales más recientes y úsalos para hacer seguimiento de costos, aplicar presupuestos o monitorear el consumo.
{
"id": "sesn_01...",
"status": "idle",
"usage": {
"input_tokens": 5000,
"output_tokens": 3200,
"cache_creation_input_tokens": 2000,
"cache_read_input_tokens": 20000
}
}input_tokens reporta los tokens de entrada no almacenados en caché y output_tokens reporta el total de tokens de salida de todas las llamadas al modelo en la sesión. Los campos cache_creation_input_tokens y cache_read_input_tokens reflejan la actividad de almacenamiento en caché de prompts. Las entradas de caché usan un TTL de 5 minutos, por lo que los turnos consecutivos dentro de esa ventana se benefician de las lecturas de caché, que reducen el costo por token.
La Consola proporciona una vista de línea de tiempo visual de tus sesiones de agente. Navega a la sección de Claude Managed Agents en la Consola para ver:
session.errorWas this page helpful?