Visualize respostas com deltas de eventos
Renderize o texto de resposta do agente como uma prévia ao vivo enquanto o modelo ainda o está gerando.
Por padrão, o texto de resposta do agente chega ao fluxo de eventos da sessão como eventos agent.message em buffer. Cada um é emitido somente depois que a requisição ao modelo que o produziu termina. Os "event deltas" (deltas de eventos) permitem que você renderize esse texto de forma incremental, como uma prévia ao vivo, enquanto o modelo ainda o está gerando.
As prévias são um auxílio de exibição de melhor esforço, e o agent.message em buffer é sempre o registro oficial. Um cliente que ignora as prévias ainda recebe um fluxo completo e correto.
Ative as prévias
As prévias são opcionais por conexão de fluxo. Adicione o parâmetro de consulta event_deltas[] ao fluxo que você está lendo e repita-o uma vez para cada tipo de evento que você deseja visualizar. Os valores aceitos são agent.message e agent.thinking. Qualquer outro valor retorna um erro 400, assim como uma requisição com mais de 100 valores.
Ambos os endpoints de fluxo aceitam o parâmetro:
- Fluxo no nível da sessão:
GET /v1/sessions/{session_id}/events/stream - Fluxo de thread da sessão:
GET /v1/sessions/{session_id}/threads/{thread_id}/stream
As prévias de um subagente aparecem no próprio fluxo de thread desse subagente.
[] é um padrão glob do shell, então coloque a URL entre aspas sempre que você construir a requisição em um shell. Os exemplos codificam os colchetes em porcentagem como %5B%5D, o que também funciona.
Eventos de prévia
Quando um evento com prévia começa, o fluxo 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 estende em event_id e o bloco de conteúdo que 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"
}
}
}Para agent.thinking, apenas o event_start é emitido, como um sinal de que um bloco de pensamento começou. Nenhum evento event_delta o segue. O evento agent.thinking em buffer que conclui a prévia é um sinal de progresso e não contém nenhum conteúdo de pensamento.
Diferentemente dos eventos persistidos, event_start e event_delta não têm id nem processed_at próprios. O único identificador que eles carregam é o id do evento que visualizam. Suas strings de tipo também são a exceção à convenção de nomenclatura {domain}.{action} dos eventos persistidos.
Acumule e reconcilie
Todo SDK que oferece suporte a deltas de eventos inclui um auxiliar acumulador que cuida da contabilidade do index para você. O padrão manual desta seção funciona em todas as linguagens quando você precisa de uma contabilidade personalizada. Aplique-o aos tipos de eventos gerados.
No padrão manual, mantenha o texto da prévia em um mapa temporário indexado por (event_id, index) e trate o evento em buffer como o registro. Reconcilie os dois por requisição ao modelo.
Um turno começa com um único evento session.status_running. Em um turno que é concluído normalmente, cada requisição ao modelo produz então estes eventos, em ordem:
span.model_request_startevent_start- Os eventos
event_delta - O
agent.messageem buffer span.model_request_end(na aba Span events)
Na transmissão, esta é a parte com prévia dessa sequência, intercalada com os outros eventos em buffer da conexão:
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": [...]}A linha event_delta se repete uma vez por fragmento de texto. Processe cada evento à medida que ele chega:
- Em
event_start, anote oidanunciado. Os identificadores sempre coincidem:event_start.event.id, cadaevent_delta.event_ide oiddoagent.messageem buffer são o mesmo valor. - Em cada
event_delta, anexedelta.content.textà entrada em(event_id, delta.index)e renderize o texto acumulado. O primeiro delta para umindexcria essa entrada. - Quando o
agent.messageem buffer chegar, associe-o peloid, descarte a prévia acumulada e renderize o conteúdo da mensagem em seu lugar. - Em
span.model_request_end, feche qualquer prévia que não tenha sido reconciliada pelo seu evento em buffer. Nenhum outro delta chegará para ela. Se o turno apresentar erro ou for interrompido, o evento em buffer pode nunca chegar, masspan.model_request_endainda chega.
O padrão depende de duas garantias:
- Concatenar os deltas de uma prévia na ordem de chegada, indexados por
(event_id, index), resulta em um prefixo decontent[index].textno evento em buffer. Não é necessariamente o texto inteiro, porque os deltas podem ser descartados sob carga. - Uma conexão emite no máximo um
event_startporevent_id, e o evento em buffer é a última coisa que essa conexão entrega para esseid.
Auxiliares acumuladores do SDK
O auxiliar de cada SDK cuida da contabilidade do index. Os auxiliares de Go, Java, Ruby e C# também indexam a prévia acumulada pelo id do evento. Com os auxiliares de Python, TypeScript e PHP, mantenha esse mapa você mesmo e incorpore cada delta à entrada do seu id.
Os exemplos a seguir ativam as prévias de agent.message e as reconciliam com o evento em buffer:
# Snapshots de prévia, indexados pelo id do evento. accumulate_managed_agents_event incorpora 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 fecha 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 virão mais deltas. Feche 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":
breakVisualize eventos de threads da sessão
Em uma sessão multiagente, cada thread da sessão tem seu próprio fluxo de eventos. Ele aceita o mesmo parâmetro event_deltas[] com os mesmos valores.
Uma conexão visualiza apenas a thread que está lendo. O fluxo no nível da sessão visualiza a thread principal, e as prévias de uma thread filha nunca são replicadas nele. Para acompanhar o texto de um subagente enquanto o modelo o gera, abra o fluxo de thread desse subagente.
O caminho de um fluxo de thread termina em /threads/{thread_id}/stream. /events/stream existe apenas no nível da sessão, portanto não há um endpoint /threads/{thread_id}/events/stream.
event_start e event_delta têm o mesmo formato em um fluxo de thread e no fluxo no nível da sessão, e o padrão de acumular e reconciliar se aplica conforme descrito. Execute uma instância de acumulador por conexão de fluxo.
# Liste as threads da sessão e escolha uma filha: threads filhas têm parent_thread_id
# não nulo, e o parent_thread_id da thread principal é null.
child_thread = next(
thread
for thread in client.beta.sessions.threads.list(session.id)
if thread.parent_thread_id is not None
)
# O stream da thread filha aceita o mesmo parâmetro event_deltas que o
# stream da sessão.
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":
# O evento em buffer é o registro oficial; renderize o conteúdo dele
print()
for block in event.content:
if block.type == "text":
print(block.text, end="")
print()
case "session.thread_status_idle":
breakO loop de leitura termina em session.thread_status_idle, o evento emitido quando o turno da thread da sessão termina e a thread fica ociosa.
Limitações
- Melhor esforço: Sob carga, o servidor pode descartar deltas de um evento. Quando isso acontece, você recebe um prefixo contíguo do texto e depois nenhum outro delta para esse evento. O
agent.messageem buffer ainda chega completo. Nunca trate uma prévia acumulada como final. - Sem reprodução ao reconectar: Os deltas são entregues apenas à conexão que os ativou, enquanto ela estiver aberta. Isso se aplica igualmente ao fluxo no nível da sessão e a cada fluxo de thread da sessão. Uma conexão aberta depois que uma requisição ao modelo começou não recebe deltas para esse evento em andamento. Não há como solicitar novamente os deltas perdidos.
- Uma thread, apenas texto: As prévias abrangem o texto do assistente na thread que a conexão está lendo. Uso de ferramentas, resultados de ferramentas e resultados de MCP nunca são visualizados.
- Nunca persistidos:
event_starteevent_deltaexistem apenas no fluxo ao vivo. Eles não aparecem no histórico de eventos da sessão (GET /v1/sessions/{session_id}/events) nem no histórico de eventos de qualquer thread da sessão.
Solucione problemas de prévias
| O que você vê | O que significa |
|---|---|
Um fluxo com eventos em buffer, mas sem event_start ou event_delta | A conexão que você está lendo não ativou as prévias, ou o turno nunca passou pela thread que você está transmitindo. event_deltas[] se aplica por conexão, não por sessão. Para descobrir qual thread foi executada, liste as threads da sessão (GET /v1/sessions/{session_id}/threads). |
| Um fluxo que cai durante uma prévia | Os deltas não são reproduzidos novamente. Siga o procedimento de reconexão: reabra o fluxo e liste o histórico de eventos. O histórico inclui todos os eventos em buffer emitidos enquanto você estava desconectado, incluindo o agent.message que sua prévia estava aguardando. |
| Um 404 na URL do fluxo | O caminho ou um ID está errado, ou a requisição não contém nenhum cabeçalho beta de managed-agents. Os endpoints de thread são restritos ao beta, então sem o cabeçalho eles não existem. |
Um 400 mencionando event_deltas | Apenas agent.message e agent.thinking são aceitos. |
Próximos passos
Envie eventos, transmita respostas e interrompa ou redirecione sua sessão durante a execução.
Coordene vários agentes em uma única sessão.
Was this page helpful?