Architecture

O SDK é uma camada de transporte — ele envia seu prompt para o Copilot CLI via JSON-RPC e retorna os eventos para o seu aplicativo. A CLI é o orquestrador que executa o ciclo de uso de ferramentas pelo agente, realizando uma ou mais chamadas à API de LLM até que a tarefa seja concluída.
O ciclo de uso de ferramentas
Quando você chama session.send({ prompt }), a CLI insere um loop:

O modelo vê o histórico completo da conversa em cada chamada — prompt do sistema, mensagem do usuário e todas as chamadas e resultados de ferramentas anteriores.
Insight principal: Cada iteração desse loop é exatamente uma chamada à API de LLM, visível no log de eventos como um par assistant.turn_start / assistant.turn_end. Não há chamadas ocultas.
Turnos – o que são
Uma curva é uma única chamada à API LLM e suas consequências:
- A CLI envia o histórico de conversas para o LLM
- O LLM responde (possivelmente com solicitações de ferramentas)
- Se as ferramentas foram solicitadas, a CLI as executa
assistant.turn_endé emitido
Normalmente, uma única mensagem de usuário resulta em várias voltas. Por exemplo, uma pergunta como "como o X funciona nessa base de código?" pode produzir:
| Virar | O que o modelo faz | toolRequests? |
|---|---|---|
| 1 | Chama grep e glob para pesquisar na base de código | |
| ✅ Sim | ||
| 2 | Lê arquivos específicos com base nos resultados da pesquisa | |
| ✅ Sim | ||
| 3 | Lê mais arquivos para um contexto mais profundo | |
| ✅ Sim | ||
| 4 | Produz a resposta de texto final | |
| ❌ Não → o loop termina |
O modelo decide em cada turno se deseja solicitar mais ferramentas ou produzir uma resposta final. Cada chamada vê o contexto acumulado completo (todas as chamadas e resultados de ferramentas anteriores), para que possa tomar uma decisão informada sobre se ela tem informações suficientes.
Fluxo de eventos para uma interação de vários turnos

Quem dispara cada turno?
| Ator | Responsabilidade |
|---|---|
| Seu aplicativo | Envia o prompt inicial por meio de session.send() |
| Copilot CLI | Executa o ciclo de uso de ferramentas — executa as ferramentas e retorna os resultados à LLM para a próxima interação |
| LLM | Decide se deve solicitar ferramentas (continuar o loop) ou produzir uma resposta final (interromper) |
| SDK | Passa eventos por meio; não controla o loop |
A CLI é puramente mecânica: "o modelo solicitou ferramentas → executá-las → chamar o modelo novamente." O modelo é o tomador de decisão para quando parar.
session.idle versus session.task_complete
Estes são dois sinais de conclusão diferentes com garantias muito diferentes:
session.idle
- Sempre emitido quando o loop de uso da ferramenta termina
- Efêmero: não persistido em disco, não reexecutado na retomada da sessão
- Significa: "o agente parou de processar e está pronto para a próxima mensagem"
- Use isso como seu sinal confiável de "concluído"
O método do sendAndWait() SDK aguarda este evento:
// Blocks until session.idle fires
const response = await session.sendAndWait({ prompt: "Fix the bug" });
session.task_complete
- Emitido opcionalmente: requer que o modelo o indique explicitamente
- Persistido: salvo no log de eventos da sessão em disco
- Significa: "o agente considera a tarefa geral atendida"
- Carrega um campo opcional
summary
session.on("session.task_complete", (event) => {
console.log("Task done:", event.data.summary);
});
Modo de piloto automático: os empurrãoes da CLI para task_complete
No modo de piloto automático (operação sem cabeça/autônoma), a CLI controla ativamente se o modelo chamou task_complete. Se o loop de uso da ferramenta terminar sem isso, a CLI injetará uma mensagem sintética de usuário para orientar o modelo:
"Você ainda não marcou a tarefa como concluída usando a ferramenta task_complete. Se você estava planejando, interrompa o planejamento e comece a implementar. Você não terminará até concluir totalmente a tarefa."
Isso reinicia efetivamente o loop de uso de ferramentas– o modelo vê o empurrão como uma nova mensagem de usuário e continua funcionando. O empurrão também instrui o modelo a não chamar task_complete prematuramente:
- Não chame se você tiver perguntas abertas, tome decisões e continue trabalhando
- Não a chame se encontrar um erro — tente resolvê-lo
- Não chame se houver etapas restantes – conclua-as primeiro
Isso cria um mecanismo de conclusão de dois níveis no piloto automático:
- O modelo chama
task_completecom um resumo → CLI emitesession.task_complete→ concluído - O modelo interrompe sem fazer a chamada → a CLI dá um aviso → o modelo continua ou chama
task_complete
Por que task_complete talvez não apareça
No modo interativo (chat normal), a CLI não solicita task_complete. O modelo pode ignorá-lo completamente. Motivos comuns:
- Q&A de conversa: o modelo responde a uma pergunta e simplesmente para — não há nenhuma "tarefa" discreta para concluir
- Critério do modelo: o modelo produz uma resposta de texto final sem chamar o sinal de conclusão da tarefa
- Sessões interrompidas: a sessão termina antes que o modelo atinja um ponto de conclusão
A CLI emite session.idle independentemente, porque é um sinal mecânico (o loop terminou), não um semântico (o modelo acha que foi feito).
Qual você deve usar?
| Caso de uso | Sinal |
|---|---|
| "Aguarde até que o agente conclua o processamento" | |
session.idle | |
| ✅ | |
| "Saiba quando uma tarefa de codificação é concluída" | |
session.task_complete (melhor esforço) | |
| "Tempo limite/tratamento de erros" | |
session.idle |
session.error
✅
|
Contagem de chamadas LLM
O número de pares assistant.turn_start / assistant.turn_end no log de eventos é igual ao número total de chamadas feitas à API LLM. Não há chamadas ocultas para planejamento, avaliação ou verificação de conclusão.
Para inspecionar a contagem de turnos de uma sessão:
# Count turns in a session's event log
grep -c "assistant.turn_start" ~/.copilot/session-state/<sessionId>/events.jsonl
Leitura adicional
- Eventos de sessão de streaming: Referência completa no nível de campo para cada tipo de evento
- Retomada e persistência da sessão: Como as sessões são salvas e retomadas
- Trabalhando com ganchos: Interceptando eventos no loop (permissões, ferramentas)