Overview
Quando streaming: true é definido em uma sessão, o SDK emite eventos efêmeros em tempo real (deltas, atualizações de progresso) junto com eventos persistentes (mensagens completas, resultados da ferramenta). Todos os eventos compartilham um envelope comum e carregam uma data carga cuja forma depende do evento type.

| Conceito | Description |
|---|---|
| Evento efêmero | Transitório; transmitido em tempo real, mas não persistido no log de sessão. Não reproduzido na retomada da sessão. |
| Evento persistente | Salvo no log de eventos da sessão no disco. Reiniciado ao retomar uma sessão. |
| Evento Delta | Uma parte efêmera de streaming (texto ou raciocínio). Acumule deltas para construir o conteúdo completo. |
parentId cadeia | Cada parentId do evento aponta para o evento anterior, formando uma lista encadeada que você pode percorrer. |
Envelope de evento
Cada evento de sessão, independentemente do tipo, inclui estes campos:
| Campo | Tipo | Description |
|---|---|---|
id | ||
string (UUID v4) | Identificador de evento exclusivo | |
timestamp | ||
string (ISO 8601) | Quando o evento foi criado | |
parentId | string | null | ID do evento anterior na cadeia; null para o primeiro evento |
agentId | string? | ID da instância do subagente para eventos originados pelo subagente; ausente para o agente raiz ou principal e para eventos no nível da sessão |
ephemeral | boolean? | |
true para eventos transitórios; ausente ou false para eventos persistentes | ||
type | string | Discriminador de tipo de evento (confira tabelas abaixo) |
data | object | Carga útil específica do evento |
Inscrevendo-se para eventos
Idiomas de código navigation
// All events
session.on((event) => {
console.log(event.type, event.data);
});
// Specific event type — data is narrowed automatically
session.on("assistant.message_delta", (event) => {
process.stdout.write(event.data.deltaContent);
});
from copilot.session_events import SessionEventType
def handle(event):
if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
print(event.data.delta_content, end="", flush=True)
session.on(handle)
session.On(func(event copilot.SessionEvent) {
if d, ok := event.Data.(*copilot.AssistantMessageDeltaData); ok {
fmt.Print(d.DeltaContent)
}
})
session.On<SessionEvent>(evt =>
{
if (evt is AssistantMessageDeltaEvent delta)
{
Console.Write(delta.Data.DeltaContent);
}
});
// All events
session.on(event -> System.out.println(event.getType()));
// Specific event type — data is narrowed to the matching class
session.on(AssistantMessageDeltaEvent.class, event ->
System.out.print(event.getData().deltaContent())
);
Dica
(Python/Go) Esses SDKs usam tipos de dados separados por evento (por exemplo, ), portanto, AssistantMessageDeltaDatasomente os campos relevantes existem em cada tipo.
(.NET) O SDK do .NET usa classes de dados separadas e fortemente tipados por evento (por exemplo, AssistantMessageDeltaData), portanto, somente os campos relevantes existem em cada tipo.
(TypeScript) O SDK do TypeScript usa uma união discriminada — quando você faz a correspondência com event.type, o payload data é automaticamente refinado para o formato correto.
Assinatura antes do início de uma sessão
Uma sessão pode emitir eventos antes que sua chamada de criação ou retomada seja retornada. O agente pode já estar em execução — especialmente na retomada com continuePendingWork — e eventos efêmeros, como session.idle, nunca são gravados no log de sessão; portanto, getMessages não consegue recuperá-los depois. Uma assinatura instalada depois que o identificador de sessão existe perde essa janela de inicialização.
Dica
(Rust)Client::prepare_session e Client::prepare_resume_session retornam um PreparedSession que detém o canal de eventos da sessão antes que qualquer atividade do protocolo ocorra. Inscreva-se primeiro e, em seguida, chame start().
use github_copilot_sdk::{Client, SessionConfig};
async fn create_without_missing_startup_events(
client: &Client,
) -> Result<(), github_copilot_sdk::Error> {
let prepared = client.prepare_session(
SessionConfig::default().with_event_buffer_capacity(2048),
)?;
// Installed before any wire activity: nothing is dropped for lack of a receiver.
let mut events = prepared.subscribe();
tokio::spawn(async move {
while let Ok(event) = events.recv().await {
println!("{}", event.event_type);
}
});
let session = prepared.start().await?;
let _ = session;
Ok(())
}
prepare_* é síncrono e inerte: valida a capacidade do buffer, aloca um canal local e não faz mais nada. Nenhuma sessão fica registrada e nada chega à CLI até que start() seja sondado pela primeira vez. Descartar uma sessão preparada que nunca foi iniciada não deixa nenhum estado para trás e fecha suas assinaturas; descartar o start() future cancela a inicialização em andamento e remove o registro da sessão, de modo que uma nova tentativa com o mesmo ID de sessão seja bem-sucedida. A limpeza é restrita ao registro específico que a inicialização abandonada detinha; portanto, ela não pode remover uma tentativa de reexecução que já tenha assumido o mesmo ID de sessão.
Vale a pena planejar o buffer de inicialização para:
- O buffer de eventos é finito— 512 eventos, a menos que
event_buffer_capacityo substitua. Uma capacidade de0é rejeitada com um erro de configuração inválida em vez de fixada. - Assinantes lentos observam um
Laggederro relatando quantos eventos foram ignorados. Eles nunca aplicam contrapressão ao loop de eventos da sessão. - Os consumidores que necessitam de uma visualização sem perdas de um grande pico de inicialização devem configurar uma capacidade que o comporte ou esvaziar a assinatura simultaneamente ao
start().
Observação
Para sessões de nuvem em que o servidor atribui a ID da sessão, o SDK não pode rotear notificações até que a resposta de criação chegue e a ID seja conhecida. Os eventos emitidos antes desse ponto não são roteáveis para nenhuma sessão. A garantia é mais limitada: os eventos roteados nunca são descartados por falta de um receptor instalado. Fixe session_id na configuração para obter roteamento (e cobertura total de pré-resposta) desde o primeiro byte.
Renderize somente a resposta do agente principal
Os eventos do subagente compartilham o fluxo da sessão principal e incluem o nível de envelope agentId. Os eventos do agente raiz/principal e os eventos de nível de sessão omitem agentId, portanto, os renderizadores do chat principal podem ignorar os eventos do assistente onde agentId está definido e encaminhar esses eventos para rastreamentos ou para a interface de progresso.
import type { CopilotSession } from "@github/copilot-sdk";
export function subscribeParentResponse(session: CopilotSession): void {
session.on("assistant.message_delta", (event) => {
if (!event.agentId) {
process.stdout.write(event.data.deltaContent);
}
});
}
from copilot import CopilotSession, SessionEvent, SessionEventType
from copilot.session_events import AssistantMessageDeltaData
def subscribe_parent_response(session: CopilotSession) -> None:
def handle(event: SessionEvent) -> None:
if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA and event.agent_id is None:
data = event.data
if isinstance(data, AssistantMessageDeltaData):
print(data.delta_content, end="", flush=True)
session.on(handle)
package example
import (
"fmt"
copilot "github.com/github/copilot-sdk/go"
)
func subscribeParentResponse(session *copilot.Session) {
session.On(func(event copilot.SessionEvent) {
if event.AgentID != nil {
return
}
if d, ok := event.Data.(*copilot.AssistantMessageDeltaData); ok {
fmt.Print(d.DeltaContent)
}
})
}
using System;
using GitHub.Copilot;
static class ParentAgentResponseExample
{
public static void SubscribeParentResponse(CopilotSession session)
{
session.On<AssistantMessageDeltaEvent>(evt =>
{
if (evt.AgentId is null)
{
Console.Write(evt.Data.DeltaContent);
}
});
}
}
import com.github.copilot.CopilotSession;
import com.github.copilot.generated.AssistantMessageDeltaEvent;
final class ParentAgentResponseExample {
static void subscribeParentResponse(CopilotSession session) {
session.on(AssistantMessageDeltaEvent.class, event -> {
if (event.getAgentId() == null) {
System.out.print(event.getData().deltaContent());
}
});
}
}
use github_copilot_sdk::session::Session;
async fn subscribe_parent_response(session: &Session) {
let mut events = session.subscribe();
while let Ok(event) = events.recv().await {
if event.event_type == "assistant.message_delta" && event.agent_id.is_none() {
if let Some(delta) = event.data.get("deltaContent").and_then(|v| v.as_str()) {
print!("{delta}");
}
}
}
}
Eventos do assistente
Esses eventos acompanham o ciclo de vida de resposta do agente, desde o início da vez, passando pelos fragmentos de streaming até a mensagem final.
assistant.turn_start
Emitido quando o agente começa a processar uma rodada.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
turnId | string | ✅ | Identificador de turno (normalmente um número de turno em cadeia de caracteres) |
interactionId | string | ID de interação CAPI para correlação de telemetria |
assistant.intent
Efêmero. Breve descrição do que o agente está fazendo no momento, atualizada conforme funciona.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
intent | string | ✅ | Intenção legível por humanos (por exemplo, "Explorando a base de código") |
assistant.reasoning
Conclua o bloco de pensamento estendido do modelo. Emitido após a conclusão do raciocínio.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
reasoningId | string | ✅ | Identificador exclusivo para esse bloco de raciocínio |
content | string | ✅ | O texto de pensamento estendido completo |
assistant.reasoning_delta
Efêmero. Bloco incremental do pensamento estendido do modelo, transmitido em tempo real.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
reasoningId | string | ✅ | Corresponde ao evento correspondente assistant.reasoning |
deltaContent | string | ✅ | Parte de texto a ser acrescentada ao conteúdo de raciocínio |
assistant.message
Resposta completa do assistente para esta chamada LLM. Pode incluir solicitações de invocação de ferramentas.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
messageId | string | ✅ | Identificador exclusivo para esta mensagem |
content | string | ✅ | Resposta de texto do assistente |
toolRequests | ToolRequest[] | Chamadas de ferramenta que o assistente deseja fazer (veja abaixo) | |
reasoningOpaque | string | Pensamento estendido criptografado (modelos antrópicos); associado à sessão | |
reasoningText | string | Texto claro de raciocínio a partir de pensamento aprofundado | |
encryptedContent | string | Conteúdo de raciocínio criptografado (modelos OpenAI); associado à sessão | |
phase | string | Fase de geração (por exemplo, "thinking" vs "response") | |
outputTokens | number | Contagem real de tokens de saída na resposta da API | |
interactionId | string | ID de interação CAPI para telemetria | |
parentToolCallId | string | Preterido. Usar o nível agentId do envelope para atribuição de subagente |
**
ToolRequest Campos:**
| Campo | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Identificação única para esta chamada de método |
name | string | ✅ | Nome da ferramenta (por exemplo, , "bash", "edit") "grep" |
arguments | object | Argumentos analisados para a ferramenta | |
type | "function" | "custom" | Tipo de chamada; é definido como "function" caso esteja ausente |
assistant.message_delta
Efêmero. Porção incremental da resposta de texto do assistente, transmitida em tempo real.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
messageId | string | ✅ | Corresponde ao evento correspondente assistant.message |
deltaContent | string | ✅ | Parte de texto a ser acrescentada à mensagem |
parentToolCallId | string | Preterido. Usar o nível agentId do envelope para atribuição de subagente |
assistant.turn_end
Emitido quando o agente conclui um turno (todas as execuções de ferramentas são concluídas, resposta final fornecida).
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
turnId | string | ✅ | Corresponde ao evento correspondente assistant.turn_start |
assistant.usage
Efêmero. Informações de uso e custo de token para uma chamada de API individual.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
model | string | ✅ | Identificador de modelo (por exemplo, "gpt-5.4") |
inputTokens | number | Tokens de entrada consumidos | |
outputTokens | number | Tokens de saída produzidos | |
reasoningTokens | number | Tokens de saída usados para raciocínio/cadeia de pensamento (subconjunto de outputTokens) | |
cacheReadTokens | number | Tokens lidos do cache de prompt | |
cacheWriteTokens | number | Tokens gravados no cache de prompt | |
cacheExpiresAt | string | Carimbo de data e hora ISO 8601 em que o cache de prompts para esta chamada de modelo expira | |
content | boolean | Se a resposta foi bloqueada ou truncada pela filtragem de conteúdo (finish_reason === 'content_filter') | |
finishReason | string | Motivo de término do modelo (por exemplo, , "stop", "length", "tool_calls", "content_filter") | |
cost | number | Custo do multiplicador de modelo para cobrança | |
duration | number | Duração da chamada à API em milissegundos | |
time | number | Hora da expedição de solicitação para o primeiro token recebido (latência de streaming) | |
inter | number | Latência média entre tokens consecutivos (taxa de transferência de streaming) | |
reasoningEffort | string | Nível de esforço de raciocínio usado para essa chamada (por exemplo, , "low", "medium") "high" | |
initiator | string | O que acionou esta chamada (por exemplo, "sub-agent"); ausente para chamadas iniciadas pelo usuário | |
apiCallId | string | ID de conclusão do provedor (por exemplo, chatcmpl-abc123) | |
serviceRequestId | string | ID da solicitação de serviço do Copilot (x-copilot-service-request-id) para correlação de logs do CAPI | |
apiEndpoint | "/ | ||
| Endpoint da API usado para a chamada ao modelo; útil para observabilidade e atribuição de custos. | |||
ws:/responses é a variante websocket da API de respostas | |||
providerCallId | string | ID de rastreamento da solicitação do GitHub (x-github-request-id) | |
parentToolCallId | string | Preterido. Usar o nível agentId do envelope para atribuição de subagente | |
quotaSnapshots | Record<string, QuotaSnapshot> | Uso de recursos por cota, chaveado pelo identificador de cota | |
copilotUsage | CopilotUsage | Detalhamento do custo detalhado do token da API |
assistant.streaming_delta
Efêmero. Indicador de progresso de rede de baixo nível – total de bytes recebidos da resposta da API de streaming.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
total | number | ✅ | Bytes cumulativos recebidos até agora |
Eventos de execução de ferramentas
Esses eventos acompanham o ciclo de vida completo de cada invocação de ferramenta, desde o modelo que solicita uma chamada de ferramenta até a execução até a conclusão.
tool.execution_start
Emitido quando uma ferramenta começa a ser executada.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Identificador exclusivo para esta chamada de ferramenta |
toolName | string | ✅ | Nome da ferramenta (por exemplo, , "bash", "edit") "grep" |
arguments | object | Argumentos analisados passados para a ferramenta | |
mcpServerName | string | Nome do servidor MCP, quando a ferramenta é fornecida por um servidor MCP | |
mcpToolName | string | Nome da ferramenta original no servidor MCP | |
parentToolCallId | string | Preterido. Usar o nível agentId do envelope para atribuição de subagente |
tool.execution_partial_result
Preterido. Use tool.shell_output para saída do terminal em tempo real. Esse evento efêmero permanece emitido junto com a substituição durante a migração; Assine apenas uma representação para evitar exibir a mesma saída duas vezes.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Corresponde ao correspondente tool.execution_start |
partialOutput | string | ✅ | Instantâneo de substituição cumulativo delimitado com stdout e stderr mesclados; não é um bloco apenas de acréscimo |
tool.shell_output
Efêmero. Saída somente para acréscimo de um comando de terminal anexado ou de um comando de terminal solicitado pelo usuário. Cada evento contém texto recentemente observado, com segredos filtrados, sem os separadores ou marcadores usados para formatar os resultados finais da ferramenta para o modelo.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Identifica a chamada de ferramenta de origem |
text | string | ✅ | Novo texto a ser acrescentado, não uma captura de substituição |
stream | "stdout" | "stderr" | "terminal" | ||
Fonte de saída; omitido significa "stdout". | |||
"terminal" identifica a saída PTY inerentemente mesclada, cuja origem stdout/stderr não pode ser recuperada | |||
sequence | number | ✅ | Inicia em zero e aumenta em todos os fluxos para esta chamada de ferramenta, em ordem de publicação observada |
text Acumular separadamente por toolCallId estream, ou unir as partes em ordem de sequência para uma exibição combinada. Um número de sequência identifica duplicatas e partes ausentes; ele não estabelece a ordenação exata entre gravações independentes do sistema operacional. Um assinante tardio pode receber uma primeira sequência maior que zero.
Esses eventos são somente ao vivo: eles não são persistidos ou reproduzidos após a retomada. Os resultados finais tool.execution_complete, a formatação voltada para o modelo e a captura de comando desanexada permanecem inalterados. O texto pode conter sequências de controle de terminal; os renderizadores devem aplicar sua manipulação normal de texto de terminal.
Um comando de terminal anexado pode continuar em execução depois de tool.execution_complete quando é executado de forma assíncrona ou continuar em execução além de initial_wait. A saída recebida ao continuar usa o toolCallId original e continua o mesmo sequence, em vez de reiniciar em zero. Os consumidores que exibem apenas chamadas ativas devem ignorar partes recebidas após a conclusão, em vez de recriar o estado de chamada concluída.
A filtragem de segredos opera em cada parte decodificada. O runtime não divide artificialmente as linhas, mas as leituras do sistema operacional podem dividir uma linha ou segredo entre partes; a reconstrução do segredo entre partes não é fornecida.
tool.execution_progress
Efêmero. Status de progresso legível por humanos de uma ferramenta em execução (por exemplo, notificações de progresso do servidor MCP).
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Corresponde ao correspondente tool.execution_start |
progressMessage | string | ✅ | Mensagem de status de progresso |
tool.execution_complete
Emitido quando uma ferramenta termina de executar— com êxito ou com um erro.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Corresponde ao correspondente tool.execution_start |
success | boolean | ✅ | Se a execução foi bem-sucedida |
model | string | Modelo que gerou essa chamada de ferramenta | |
interactionId | string | ID de interação CAPI | |
isUserRequested | boolean | ||
true quando o usuário solicitou explicitamente essa chamada de ferramenta | |||
result | Result | Presente no êxito e em caso de falha quando a ferramenta retornou o conteúdo com seu erro (veja abaixo) | |
error | { message, code? } | Apresentar em caso de falha | |
toolTelemetry | object | Telemetria específica da ferramenta (por exemplo, contagem de verificações do CodeQL) | |
parentToolCallId | string | Preterido. Usar o nível agentId do envelope para atribuição de subagente |
**
Result Campos:**
| Campo | Tipo | Obrigatório | Description |
|---|---|---|---|
content | string | ✅ | Resultado conciso enviado para a LLM (pode ser truncado para eficiência de token) |
detailedContent | string | Resultado completo para exibição, preservando conteúdo completo como diffs | |
contents | ContentBlock[] | Blocos de conteúdo estruturados (texto, terminal, imagem, áudio, recurso) |
tool.user_requested
Emitido quando o usuário solicita explicitamente uma invocação de ferramenta (em vez do modelo optando por chamar uma).
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Identificador exclusivo para esta chamada de ferramenta |
toolName | string | ✅ | Nome da ferramenta que o usuário deseja invocar |
arguments | object | Argumentos para a invocação |
Eventos de ciclo de vida da sessão
session.idle
Efêmero. O agente concluiu todo o processamento e está pronto para a próxima mensagem. Esse é o sinal de que uma curva está totalmente concluída.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
aborted | boolean | Verdadeiro quando a rodada anterior foi cancelada por meio de um sinal de anulação |
session.error
Ocorreu um erro durante o processamento da sessão.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
errorType | string | ✅ | Categoria de erro (por exemplo, , "authentication", "quota") "rate_limit" |
message | string | ✅ | Mensagem de erro legível por humanos |
stack | string | Rastreamento de pilha de erros | |
statusCode | number | Código de status HTTP da solicitação upstream | |
providerCallId | string | ID de rastreamento da solicitação do GitHub para correlação de logs do lado do servidor |
session.compaction_start
A compactação da janela de contexto começou.
A carga de dados está vazia ({}).
session.compaction_complete
Compactação da janela de contexto concluída.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
success | boolean | ✅ | Se a compactação foi bem-sucedida |
error | string | Mensagem de erro se a compactação falhou | |
pre | number | Tokens anteriores à compactação | |
post | number | Tokens após a compactação | |
pre | number | Contagem de mensagens antes da compactação | |
messagesRemoved | number | Mensagens removidas | |
tokensRemoved | number | Tokens removidos | |
summaryContent | string | Resumo do histórico compactado gerado por LLM | |
checkpointNumber | number | Número de instantâneo de ponto de verificação criado para recuperação | |
checkpointPath | string | Caminho do arquivo onde o ponto de verificação foi armazenado | |
compaction | { input, output, cachedInput } | Uso de token para a chamada LLM de compactação | |
requestId | string | ID de rastreamento da solicitação do GitHub para a chamada de compactação |
session.title_changed
Efêmero. O título gerado automaticamente da sessão foi atualizado.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
title | string | ✅ | Novo título da sessão |
session.context_changed
O diretório de trabalho ou o contexto do repositório da sessão foi alterado.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
cwd | string | ✅ | Diretório de trabalho atual |
gitRoot | string | Raiz do repositório Git | |
repository | string | Repositório em "owner/name" formato | |
branch | string | Branch atual do Git |
session.usage_info
Efêmero. Instantâneo de utilização da janela de contexto.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
tokenLimit | number | ✅ | Tokens máximos para a janela de contexto do modelo |
currentTokens | number | ✅ | Tokens atuais na janela de contexto |
messagesLength | number | ✅ | Contagem de mensagens atual na conversa |
session.session_limits_changed
Os limites da sessão foram alterados para o período contábil atual. Um null``sessionLimits valor significa que nenhum limite está ativo.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
sessionLimits | Session | ✅ | Limites de sessão atuais ou null quando nenhum limite está ativo |
session | number | Máximo de créditos de IA permitidos durante a janela de contabilização atual da sessão |
session.usage_checkpoint
Ponto de verificação durável do uso agregado usado para reconstruir a contabilização quando uma sessão é retomada.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
totalNanoAiu | number | ✅ | Custo das unidades de nano-IA acumuladas ao longo da sessão no ponto de verificação |
total | number | Número total de solicitações de API premium usadas no momento do ponto de verificação |
session.task_complete
O agente concluiu sua tarefa atribuída.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
summary | string | Resumo da tarefa concluída |
session.shutdown
A sessão foi encerrada.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
shutdownType | "routine" | "error" | ✅ | Desligamento normal ou falha |
errorReason | string | Descrição do erro quando shutdownType é "error" | |
total | number | ✅ | Total de solicitações de API Premium usadas |
total | number | ✅ | Tempo de chamada da API cumulativa em milissegundos |
sessionStartTime | number | ✅ | Timestamp Unix (ms) quando a sessão começou |
codeChanges | { linesAdded, linesRemoved, filesModified } | ✅ | Métricas agregadas de alteração de código |
modelMetrics | Record<string, ModelMetric> | ✅ | Detalhamento de uso por modelo |
currentModel | string | Modelo selecionado durante o desligamento |
Eventos de permissão e de interação do usuário
Esses eventos são emitidos quando o agente precisa de aprovação ou entrada do usuário antes de continuar.
permission.requested
O agente precisa de permissão para executar uma ação (executar um comando, gravar um arquivo etc.).
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Use isso para responder via session.respond |
permissionRequest | PermissionRequest | ✅ | Detalhes da permissão que está sendo solicitada |
A permissionRequest é uma união discriminada de kind:
kind | Campos importantes | Description |
|---|---|---|
"shell" | ||
fullCommandText, intention, , commands[]``possible | Executar um comando de shell | |
"write" | ||
fileName, diff, intention, , new | Gravar/modificar um arquivo | |
"read" | ||
path, intention | Ler um arquivo ou diretório | |
"mcp" | ||
serverName, toolName, toolTitle, , args?``readOnly | Chamar uma ferramenta MCP | |
"url" | ||
url, intention | Recuperar uma URL | |
"memory" | ||
subject, fact, citations | Armazenar uma memória | |
"custom-tool" | ||
toolName, toolDescription, args? | Chamar uma ferramenta personalizada |
Todas as variantes kind também incluem uma vinculação opcional toolCallId de volta à chamada de ferramenta que disparou a solicitação.
Solicitações de gravação também podem incluir fileEdits em permissionRequest e promptRequest. Cada entrada contém instantâneos opcionais before e after, cada um com um path absoluto no namespace do sistema de arquivos da sessão e content UTF-8 completo. A ausência de before significa criação; a ausência de after significa exclusão. Uma cadeia de caracteres vazia content representa um arquivo vazio, não uma visualização indisponível. Um movimento pode ter caminhos diferentes em seus dois lados. Quando um movimento substitui um destino existente, entradas separadas descrevem a exclusão de origem e a substituição de destino.
Esses instantâneos descrevem a operação planejada, não uma leitura posterior do sistema de arquivos ativo. O runtime omite fileEdits quando não pode fornecer uma visualização de texto completa, incluindo solicitações feitas antes de ler um arquivo protegido por área restrita, conteúdo não UTF-8 ou um destino de movimentação ilegível ou não regular, como um pipe nomeado. Não infera uma exclusão de um valor herdado newFileContents vazio. Os campos existentes e as opções de aprovação permanecem disponíveis para consumidores que não usam visualizações.
permission.completed
Uma solicitação de permissão foi resolvida.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Corresponde ao correspondente permission.requested |
result.kind | string | ✅ | Um de: "approved", "denied-by-rules", "denied-interactively-by-user", "denied-no-approval-rule-and-could-not-request-from-user", "denied-by-content-exclusion-policy" |
user_input.requested
Efêmero. O agente está fazendo uma pergunta ao usuário.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Use isso para responder via session.respond |
question | string | ✅ | A pergunta a ser apresentada ao usuário |
choices | string[] | Opções predefinidas para o usuário | |
allowFreeform | boolean | Se a entrada de texto de forma livre é permitida |
user_input.completed
Efêmero. Uma solicitação de entrada do usuário foi resolvida.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Corresponde ao correspondente user_input.requested |
elicitation.requested
Efêmero. O agente precisa de entrada estruturada de dados do usuário (protocolo de elicitação MCP).
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Use isso para responder via session.respond |
message | string | ✅ | Descrição de quais informações são necessárias |
mode | "form" | Modo de elicitação (no momento, somente "form") | |
requestedSchema | { type: "object", properties, required? } | ✅ | Esquema JSON que descreve os campos de formulário |
elicitation.completed
Efêmero. Uma solicitação de elicitação foi resolvida.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Corresponde ao correspondente elicitation.requested |
Eventos de subagente e habilidade
subagent.started
Um agente personalizado foi invocado como um subagente.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Chamada de ferramenta-mãe que gerou este subagente |
agentName | string | ✅ | Nome interno do subagente |
agentDisplayName | string | ✅ | Nome de exibição legível por humanos |
agentDescription | string | ✅ | Descrição do que o subagente faz |
model | string | Modelo com o qual o subagente será executado, quando isso for conhecido desde o início |
subagent.completed
Um subagente concluiu com sucesso.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Corresponde ao correspondente subagent.started |
agentName | string | ✅ | Nome interno |
agentDisplayName | string | ✅ | Nome de exibição |
model | string | Modelo usado pelo subagente | |
durationMs | number | Duração da execução em milissegundos (tempo real) | |
totalTokens | number | Total de tokens de entrada e saída consumidos | |
totalToolCalls | number | Total de chamadas de ferramenta realizadas |
subagent.failed
Um subagente encontrou um erro.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
toolCallId | string | ✅ | Corresponde ao correspondente subagent.started |
agentName | string | ✅ | Nome interno |
agentDisplayName | string | ✅ | Nome de exibição |
error | string | ✅ | Mensagem de erro |
model | string | Modelo selecionado para o subagente, quando conhecido | |
durationMs | number | Duração da execução em milissegundos (tempo real) | |
totalTokens | number | Total de tokens de entrada e saída consumidos antes da falha | |
totalToolCalls | number | Total de chamadas de ferramenta feitas antes da falha |
subagent.selected
Um agente personalizado foi selecionado (inferido) para lidar com a solicitação atual.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
agentName | string | ✅ | Nome interno do agente selecionado |
agentDisplayName | string | ✅ | Nome de exibição |
tools | string[] | null | ✅ | Nomes de ferramentas disponíveis para este agente; null para todas as ferramentas |
subagent.deselected
Um agente personalizado foi desselecionado, retornando ao agente padrão.
A carga de dados está vazia ({}).
skill.invoked
Uma habilidade foi ativada para a conversa atual.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
name | string | ✅ | Nome da habilidade |
path | string | ✅ | Caminho do arquivo para a definição de SKILL.md |
content | string | ✅ | Conteúdo completo da habilidade injetado na conversa |
allowedTools | string[] | Ferramentas listadas no frontmatter da allowed-tools skill. O SDK não os aprova automaticamente; o manipulador de permissões ainda decide. A CLI Copilot os aprova automaticamente enquanto a habilidade está ativa. | |
pluginName | string | Plugin da habilidade de origem | |
pluginVersion | string | Versão do plug-in |
Outros eventos
abort
O turno atual foi abortado.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
reason | string | ✅ | Por que o turno foi abortado (por exemplo, "user initiated") |
user.message
O usuário enviou uma mensagem. Gravado na linha do tempo da sessão.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
content | string | ✅ | O texto da mensagem do usuário |
transformed | string | Versão transformada após o pré-processamento | |
attachments | Attachment[] | Anexos de arquivo, diretório, seleção, blob ou referência do GitHub | |
source | string | Identificador de origem da mensagem | |
agentMode | string | Modo de agente: "interactive", , "plan", "autopilot"ou "shell" | |
interactionId | string | ID de interação CAPI |
system.message
Um prompt do sistema ou do desenvolvedor foi injetado na conversa.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
content | string | ✅ | O texto do prompt |
role | "system" | "developer" | ✅ | Função de mensagem |
name | string | Identificador de origem | |
metadata | { promptVersion?, variables? } | Metadados do modelo de prompt |
external_tool.requested
O agente deseja invocar uma ferramenta externa (uma fornecida pelo consumidor do SDK).
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Use isso para responder via session.respond |
sessionId | string | ✅ | Sessão à qual esta solicitação pertence |
toolCallId | string | ✅ | ID de chamada de ferramenta para essa invocação |
toolName | string | ✅ | Nome da ferramenta externa |
arguments | object | Argumentos para a ferramenta |
external_tool.completed
Uma solicitação de ferramenta externa foi resolvida.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Corresponde ao correspondente external_tool.requested |
exit_plan_mode.requested
Efêmero. O agente criou um plano e deseja sair do modo de plano.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Use isso para responder via session.respond |
summary | string | ✅ | Resumo do plano |
planContent | string | ✅ | Conteúdo completo do arquivo de plano |
actions | string[] | ✅ | Ações de usuário disponíveis (por exemplo, aprovar, editar, rejeitar) |
recommendedAction | string | ✅ | Ação sugerida |
exit_plan_mode.completed
Efêmero. Uma solicitação de modo de plano de saída foi resolvida.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Corresponde ao correspondente exit_plan_mode.requested |
command.queued
Efêmero. Um comando barra "/" foi colocado na fila para execução.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Use isso para responder via session.respond |
command | string | ✅ | O texto do comando de barra (por exemplo, /help, /clear) |
command.completed
Efêmero. Um comando enfileirado foi resolvido.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Corresponde ao correspondente command.queued |
session_limits_exhausted.requested
Efêmero. O orçamento atual da sessão foi esgotado e o runtime precisa de uma decisão do usuário antes de continuar.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Use este ID ao responder à solicitação pendente de limite esgotado |
maxAiCredits | number | ✅ | Créditos máximos de IA configurados para a janela de contabilidade atual |
usedAiCredits | number | ✅ | Créditos de IA já consumidos na janela de contabilidade atual |
session_limits_exhausted.completed
Efêmero. Uma solicitação pendente de limite esgotado foi resolvida.
| Campo de dados | Tipo | Obrigatório | Description |
|---|---|---|---|
requestId | string | ✅ | Corresponde ao evento correspondente session_limits_ |
response.action | "add" | "set" | "unset" | "cancel" | ✅ | Ação selecionada para a solicitação de limite esgotado |
response.additional | number | Créditos de IA a serem adicionados ao máximo atual quando response.action estiver "add" | |
response.max | number | Novos créditos absolutos máximos de IA quando response.action é "set" |
Referência rápida: fluxo de agentes em turnos
Uma rodada de agente típica emite eventos nesta ordem:
assistant.turn_start → Turn begins
├── assistant.intent → What the agent plans to do (ephemeral)
├── assistant.reasoning_delta → Streaming thinking chunks (ephemeral, repeated)
├── assistant.reasoning → Complete thinking block
├── assistant.message_delta → Streaming response chunks (ephemeral, repeated)
├── assistant.message → Complete response (may include toolRequests)
├── assistant.usage → Token usage for this API call (ephemeral)
│
├── [If tools were requested:]
│ ├── permission.requested → Needs user approval
│ ├── permission.completed → Approval result
│ ├── tool.execution_start → Tool begins
│ ├── tool.shell_output → Stream-tagged terminal output (ephemeral, repeated)
│ ├── tool.execution_progress → Progress updates (ephemeral, repeated)
│ ├── tool.execution_complete → Tool finished
│ │
│ └── [Agent loops: more reasoning → message → tool calls...]
│
assistant.turn_end → Turn complete
session.idle → Ready for next message (ephemeral)
Todos os tipos de evento em um relance
Esta tabela lista os principais data campos de conteúdo. Campos de envelope comuns estão documentados acima.
| Tipo de evento | Efêmero | Categoria | Campos de dados de chave |
|---|---|---|---|
assistant.turn_start | |||
| Assistente | |||
turnId, interactionId? | |||
assistant.intent | ✅ | Assistente | intent |
assistant.reasoning | |||
| Assistente | |||
reasoningId, content | |||
assistant.reasoning_delta | ✅ | Assistente | |
reasoningId, deltaContent | |||
assistant.streaming_delta | ✅ | Assistente | total |
assistant.message | |||
| Assistente | |||
messageId, content, toolRequests?, , output | |||
assistant.message_delta | ✅ | Assistente | |
messageId, deltaContent | |||
assistant.turn_end | Assistente | turnId | |
assistant.usage | ✅ | Assistente | |
model, apiEndpoint?, inputTokens?, outputTokens?, , cost?``duration? | |||
tool.user_requested | |||
| Tool | |||
toolCallId, toolName, arguments? | |||
tool.execution_start | |||
| Tool | |||
toolCallId, toolName, , arguments?``mcp | |||
tool.execution_partial_ | ✅ | Tool | |
toolCallId, partialOutput | |||
tool.shell_output | ✅ | Tool | |
toolCallId, text, , stream?``sequence | |||
tool.execution_progress | ✅ | Tool | |
toolCallId, progressMessage | |||
tool.execution_complete | |||
| Tool | |||
toolCallId, success, , result?``error? | |||
session.idle | ✅ | Session | aborted? |
session.error | |||
| Session | |||
errorType, message, statusCode? | |||
session.compaction_start | |||
| Session | |||
| (vazio) | |||
session.compaction_complete | |||
| Session | |||
success, pre, summaryContent? | |||
session.title_changed | ✅ | Session | title |
session.context_changed | |||
| Session | |||
cwd, gitRoot?, , repository?``branch? | |||
session.usage_info | ✅ | Session | |
tokenLimit, currentTokens, messagesLength | |||
session.session_limits_ | Session | sessionLimits | |
session.usage_checkpoint | |||
| Session | |||
totalNanoAiu, total | |||
session.task_complete | Session | summary? | |
session.shutdown | |||
| Session | |||
shutdownType, codeChanges, modelMetrics | |||
permission.requested | |||
| Permissão | |||
requestId, permissionRequest | |||
permission.completed | |||
| Permissão | |||
requestId, result.kind | |||
user_input.requested | ✅ | Entrada do usuário | |
requestId, question, choices? | |||
user_input.completed | ✅ | Entrada do usuário | requestId |
elicitation.requested | ✅ | Entrada do usuário | |
requestId, message, requestedSchema | |||
elicitation.completed | ✅ | Entrada do usuário | requestId |
subagent.started | |||
| Subagente | |||
toolCallId, agentName, , agent | |||
subagent.completed | |||
| Subagente | |||
toolCallId, agentName, agentDisplayName, model?, , durationMs?, totalTokens?, totalToolCalls? | |||
subagent.failed | |||
| Subagente | |||
toolCallId, agentName, error, model?, , durationMs?, totalTokens?, totalToolCalls? | |||
subagent.selected | |||
| Subagente | |||
agentName, agentDisplayName, tools | |||
subagent.deselected | |||
| Subagente | |||
| (vazio) | |||
skill.invoked | |||
| Habilidade | |||
name, path, , content``allowed | |||
abort | Controle | reason | |
user.message | |||
| Usuário | |||
content, attachments?, agentMode? | |||
system.message | |||
| System | |||
content, role | |||
external_tool.requested | |||
| Ferramenta Externa | |||
requestId, toolName, arguments? | |||
external_tool.completed | Ferramenta Externa | requestId | |
command.queued | ✅ | Command | |
requestId, command | |||
command.completed | ✅ | Command | requestId |
session_limits_ | ✅ | Session | |
requestId, maxAiCredits, usedAiCredits | |||
session_limits_ | ✅ | Session | |
requestId, response.action | |||
exit_plan_mode.requested | ✅ | Modo Planejamento | |
requestId, summary, , plan | |||
exit_plan_mode.completed | ✅ | Modo Planejamento | requestId |