A comunicação com Claude Managed Agents é baseada em eventos. Você envia eventos de usuário para o agente e recebe de volta eventos de agente e de sessão para acompanhar o status.
Todas as requisições à Managed Agents API exigem o cabeçalho beta managed-agents-2026-04-01. O SDK define o cabeçalho beta automaticamente.
Os eventos fluem em duas direções.
user.* iniciam uma sessão e a direcionam conforme ela progride; system.message atualiza o prompt do sistema do agente entre turnos.As strings de tipo de evento de sessão, span, agente, usuário e sistema seguem a convenção de nomenclatura {domain}.{action}. Os eventos de prévia de delta exclusivos de stream (event_start, event_delta) são a exceção. Consulte Tipos de eventos na referência para o catálogo completo.
Todo evento persistido inclui um timestamp processed_at indicando quando o evento foi registrado no lado do servidor. Se processed_at for null, significa que o evento foi enfileirado pelo harness e é tratado depois que os eventos anteriores terminam de ser processados.
Por padrão, o texto de resposta do agente chega ao stream como eventos agent.message em buffer, cada um emitido apenas depois que a requisição ao modelo que o produziu termina. Os deltas de eventos permitem que você renderize esse texto de forma incremental, como uma prévia ao vivo, enquanto o modelo ainda está gerando. Uma prévia não é a resposta: prévias são um auxílio de exibição de melhor esforço, e o agent.message em buffer é sempre o registro autoritativo. Um cliente que ignora prévias ainda recebe um stream completo e correto.
As prévias são opcionais por conexão de stream. Adicione o parâmetro de query event_deltas[] a GET /v1/sessions/{session_id}/events/stream, repetindo-o uma vez para cada tipo de evento que você deseja visualizar como prévia. Os valores aceitos são agent.message e agent.thinking; qualquer outro valor retorna um erro 400. Apenas o stream de eventos no nível da sessão suporta o parâmetro. Streams de eventos de threads de sessão o rejeitam.
Quando um evento com prévia começa, o stream emite um event_start contendo o tipo e o id do evento que está por vir:
{
"type": "event_start",
"event": {
"type": "agent.message",
"id": "sevt_01abc..."
}
}Para agent.message, o início é seguido por eventos event_delta contendo texto incremental. Cada delta nomeia o evento que ele estende em event_id e o bloco de conteúdo que ele estende em delta.index:
{
"type": "event_delta",
"event_id": "sevt_01abc...",
"delta": {
"type": "content_delta",
"index": 0,
"content": {
"type": "text",
"text": "Here is the summary"
}
}
}Quando um evento agent.thinking é visualizado como prévia, apenas o event_start é emitido. Nenhum evento event_delta segue, e o conteúdo chega no evento agent.thinking em buffer como de costume.
Diferentemente dos eventos persistidos, event_start e event_delta não têm id ou processed_at próprios. O único identificador que eles carregam é o id do evento que eles antecipam.
Os deltas de eventos usam um formato de transmissão diferente de Streaming de mensagens, e a diferença é intencional. Um agent.message com prévia recebe um único event_start seguido apenas por eventos event_delta. Não há eventos de início ou fim por bloco de conteúdo e nenhum evento de fim para o próprio evento com prévia. O tipo de delta é content_delta, não content_block_delta. Código de acumulador escrito para a Messages API não é transferível sem alterações.
Os SDKs de Python, TypeScript e Go incluem um helper de acumulador que indexa a prévia pelo id do evento e cuida da contabilidade de index para você. O padrão manual funciona em todas as linguagens: nos outros SDKs, aplique-o aos tipos de eventos gerados.
No padrão manual, trate a prévia como um buffer de rascunho e o evento em buffer como o registro. Indexe o buffer por (event_id, index). Reconcilie por requisição ao modelo: um turno abre com um único evento session.status_running, então em um turno que completa normalmente cada requisição ao modelo produz, em ordem, span.model_request_start, event_start, os eventos event_delta, o agent.message em buffer e, finalmente, span.model_request_end (na aba de eventos de Span). Processe cada evento conforme ele chega:
event_start, anote o id anunciado. Os identificadores sempre se alinham: event_start.event.id, cada event_delta.event_id e o id do agent.message em buffer são o mesmo valor.event_delta, anexe delta.content.text à entrada em (event_id, delta.index) e renderize o texto acumulado. O primeiro delta para um index cria essa entrada.agent.message em buffer chegar, faça a correspondência por id, descarte a prévia acumulada e renderize o conteúdo da mensagem em seu lugar.span.model_request_end, feche qualquer prévia que não tenha sido reconciliada por seu evento em buffer. Nenhum delta adicional está chegando para ela. Se o turno gerar erro ou for interrompido, o evento em buffer pode nunca chegar; span.model_request_end ainda chega.# Snapshots de prévia, indexados por id de evento. accumulate_managed_agents_event consolida cada
# event_start / event_delta em um snapshot de agent.message; o agent.message
# em buffer o substitui.
previews: dict[str, BetaManagedAgentsAgentMessageEvent] = {}
# Ative as prévias de agent.message nesta conexão
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":
# O evento em buffer é o registro: ele substitui e encerra a prévia
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":
# Não há mais deltas chegando. Encerre qualquer prévia cujo
# evento em buffer nunca chegou.
for event_id in previews:
print(f"span.model_request_end closing preview for {event_id}")
previews.clear()
case "session.status_idle":
breakAs prévias são ajustadas para responsividade. Desenvolva considerando estas restrições:
agent.message em buffer ainda chega completo. Nunca trate uma prévia acumulada como final.agent.message que sua prévia estava aguardando. Não há como solicitar novamente deltas perdidos.agent.thinking apenas com início: Uma prévia de agent.thinking emite apenas o event_start como um sinal de que um bloco de pensamento começou; nenhum evento event_delta o segue.event_start e event_delta existem apenas no stream ao vivo. Eles não aparecem no histórico de eventos da sessão (GET /v1/sessions/{session_id}/events).Quando o agente invoca uma ferramenta personalizada:
agent.custom_tool_use contendo o nome da ferramenta e a entrada.session.status_idle contendo stop_reason: requires_action. Os IDs de eventos bloqueantes estão no array stop_reason.event_ids.user.custom_tool_result para cada um, passando o ID do evento no parâmetro custom_tool_use_id junto com o conteúdo do 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:
# Busque o evento de uso de ferramenta personalizada e execute-o
tool_event = events_by_id[event_id]
result = call_tool(tool_event.name, tool_event.input)
# Envie o resultado de volta
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":
breakQuando uma política de permissão requer confirmação antes de uma ferramenta ser executada:
agent.tool_use ou agent.mcp_tool_use.session.status_idle contendo stop_reason: requires_action. Os IDs de eventos bloqueantes estão no array stop_reason.event_ids.user.tool_confirmation para cada um, passando o ID do evento no parâmetro tool_use_id. Defina result como "allow" ou "deny". Use deny_message para explicar uma negação.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:
# Aprove a chamada de ferramenta pendente
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
},
],
)
case "end_turn":
breakAs sessões persistem entre interações. O histórico de conversas é preservado a menos que a sessão seja explicitamente excluída. Quando uma sessão fica ociosa, seu sandbox passa por checkpoint, preservando o estado completo do sandbox, incluindo o sistema de arquivos, pacotes instalados e quaisquer arquivos que o agente criou. Isso permite que você retome de forma limpa após inatividade.
Embora o histórico da sessão seja persistido até ser excluído, os checkpoints são preservados apenas por 30 dias após a última atividade da sessão. Se o seu fluxo de trabalho exigir que o estado completo do sandbox (arquivos, ferramentas instaladas e assim por diante) persista além de 30 dias, envie eventos user.message periódicos para reiniciar o temporizador de inatividade antes que o checkpoint expire.
Para retomar uma sessão, envie um evento user.message para ela como de costume:
# Em produção, passe o ID armazenado da sessão que você deseja retomar.
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 atualmente é suportado apenas pelo Claude Opus 4.8. Se qualquer modelo configurado no agente não suportar injeção de sistema no meio da conversa, o evento é rejeitado com um erro de validação model_does_not_support_mid_conversation_system.
Envie um evento system.message para atualizar o prompt do sistema do agente entre turnos. Diferentemente do campo system na definição do agente (que é fixado na criação da sessão), system.message permite que você altere o prompt do sistema conforme a sessão progride. Use-o quando o agente precisar de orientação atualizada no nível de sistema durante a sessão: uma persona diferente, restrições revisadas ou contexto obtido em tempo de execução que deve moldar o comportamento do modelo daqui em diante.
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 não pode ser enviado enquanto a sessão está ociosa com stop_reason: requires_action. content aceita de 1 a 1000 itens de texto.
O objeto de sessão inclui um campo usage com estatísticas cumulativas de tokens. Busque a sessão depois que ela ficar ociosa para ler os totais mais recentes e use-os para rastrear custos, aplicar orçamentos ou monitorar 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 tokens de entrada não armazenados em cache e output_tokens reporta o total de tokens de saída em todas as chamadas de modelo na sessão. Os campos cache_creation_input_tokens e cache_read_input_tokens refletem a atividade de cache de prompt. As entradas de cache usam um TTL de 5 minutos, então turnos consecutivos dentro dessa janela se beneficiam de leituras de cache, que reduzem o custo por token.
O Console fornece uma visualização de linha do tempo das suas sessões de agente. Navegue até a seção Claude Managed Agents no Console para ver:
session.errorWas this page helpful?