Saltar para o conteúdo

Ciclo de vida do despacho de agentes

Um despacho é uma execução de um agente, numa conversa, num adaptador. Tudo o que lhe diz respeito acontece no cc_server: o cliente envia uma mensagem e depois vê os eventos a voltar em fluxo. Não existe qualquer caminho de despacho em nenhum cliente.

Os agentes são despertados por seis motivos, que a execução transporta como o seu contexto de despertar, para que o agente saiba porquê está desperto:

Motivo de despertar Gatilho
userMessage Alguém enviou uma mensagem num espaço, ou mencionou o agente
assignment Foi atribuído um ticket ao agente
pipelineStep Um passo de pipeline despachou-o
childCompleted Um ticket filho terminou
followUp Um batimento de acompanhamento agendado
recovery O caminho de recuperação voltou a despachar após uma falha

O contexto de despertar transporta os ids que acompanham o motivo — ticket, espaço, mensagem, execução de pipeline — e estes são injetados no ambiente e no prompt do agente.

O prompt é construído em camadas, cada uma delas uma secção etiquetada:

  • Identidade — o id, o nome e o id do espaço de trabalho do próprio agente, com uma instrução explícita para passar esses UUIDs exatos às ferramentas com âmbito de espaço de trabalho. O espaço de trabalho é intrínseco ao agente, por isso está sempre presente.
  • Catálogo de ferramentas e protocolos de recursos, depois a disposição do espaço de trabalho.
  • Substituição do prompt de sistema, se o agente tiver uma, depois a persona (parametrizada pelo papel) e o briefing da equipa.
  • Skills — os nomes associados ao agente.
  • Contrato e procedimento de execução para o modo atual.
  • Contexto de despertar e contexto de menção: quem convocou o agente e a lista à sua volta.
  • Bloco de modo — gerado a partir do perfil de capacidades do modo e da respetiva lista de ferramentas materializada, para que um prompt nunca possa nomear uma ferramenta que a execução não tem de facto.
  • Contexto de memória — factos recuperados para a tarefa.
  • Contexto de conversa — histórico recente do espaço, limitado a 50 000 caracteres de janela de texto integral, independentemente do tamanho de contexto configurado para o agente. O histórico mais antigo não é descartado: o agente recupera-o a pedido com get_messages e as mensagens mais antigas semanticamente relevantes continuam a aparecer.

Os comandos repartem-se por dois locais. /todo e /compact são intercetados no compositor e, deliberadamente, nunca são persistidos como mensagens nem enviados ao agente — persistir /compact faria recuar o corte de compactação um turno e poluiria a transcrição. /plan é tratado nos dois: o compositor alterna o modo do espaço, e é isso que faz com que a superfície de ferramentas, a predefinição das barreiras e o prompt concordem neste turno e em todos os seguintes. /goal, /loop e /skill:<name> são tratados dentro da própria execução e apenas no harness integrado — /goal e /loop iniciam trabalho autónomo com um orçamento de custos, e um nome com o prefixo skill: é procurado como uma skill cujo corpo do SKILL.md passa a ser a diretiva do turno. É o espaço de nomes que mantém os dois vocabulários separados: resolver um nome simples contra as skills fazia com que uma skill chamada plan ou compact ficasse permanentemente ofuscada pela integrada. Um nome simples que não seja integrado continua a ser resolvido, para mensagens escritas antes de o espaço de nomes existir. Um nome não reconhecido passa simplesmente como texto simples.

Antes de qualquer coisa correr, a conversa recebe a sua própria raiz de trabalho, com uma worktree copy-on-write isolada por repo por baixo dela. Por predefinição, são todos os repos ligados ao espaço de trabalho; um espaço de PR — ou um espaço criado com uma seleção explícita — provisiona apenas os que constam da lista de permissões, e uma conversa de revisão de PR fixa o seu único repo à head ref da pull request, enquanto os restantes ficam no branch predefinido. O checkout de origem nunca é alterado e todo o diretório da conversa é libertado quando o espaço é eliminado.

A copy-on-write é a única implementação onde rift existe, suportada pelo nativo incluído. Um sistema de ficheiros que não consiga fazer reflink — ou um diretório de dados num volume diferente do repo — falha o provisionamento em vez de recorrer a uma alternativa. git worktree é o backend no Windows, onde não há backend de copy-on-write para construir, e não é uma degradação silenciosa nos outros anfitriões. Um rift em falta numa plataforma que o inclui é uma instalação avariada — o servidor recusa-se a arrancar em vez de recorrer silenciosamente a uma alternativa, porque uma alternativa silenciosa esconde a avaria por trás de um caminho mais lento para sempre.

Duas identidades são resolvidas por execução, antes de qualquer processo ser lançado.

Autoria Git. Os commits que um agente faz são assinados como o agente — <Name> (agent) <agentId@agents.control-center.local> tanto em GIT_AUTHOR_* como em GIT_COMMITTER_* —, nunca se fazendo passar por um humano. A parte local é o UUID do agente, não o slug do seu nome. O humano que fez o pedido é creditado com um trailer Co-Authored-By:, transportado no ambiente e indicado no prompt de sistema. Uma identidade definida explicitamente por quem chama prevalece sempre sobre ambas.

Identidade na forge. A credencial do GitHub da execução é sempre apenas a do corretor — um token de instalação da App com âmbito ao repo, ou a sua alternativa de PAT vinda do ambiente —, nunca o token guardado do próprio membro que fez o pedido. actingUserId limita a alternativa do PAT, para que um membro que não seja o proprietário do servidor não herde o alcance do servidor; não sobrepõe um token pessoal ao ambiente do agente.

As credenciais do fornecedor de modelos são resolvidas por uma ordem fixa, e a ordem é importante:

  1. uma substituição de ambiente por adaptador,
  2. o ambiente de quem chama,
  3. o armazenamento de credenciais do servidor (renovando um token OAuth se estiver perto de expirar),
  4. o ambiente do processo.

Como a substituição por adaptador vem primeiro, sobrepõe-se silenciosamente a uma conta de fornecedor ligada na aplicação. Se uma execução estiver a ser cobrada à conta errada, essa substituição é o primeiro sítio onde procurar. As credenciais dos fornecedores são globais ao anfitrião — partilhadas por todos os espaços de trabalho da instalação.

O token do GitHub da execução vem do corretor de credenciais: um token só de leitura, limitado ao repositório da worktree. Um push passa pelo gateway de execuções de agentes, que pergunta à regra Fazer push para um remoto antes de o reencaminhar, e nenhuma chave de tickets é injetada. Ver Sandbox e segurança.

A execução é lançada com a sua worktree como diretório de trabalho e — no caso do Claude Code — com uma configuração MCP gerada, para que o agente possa chegar à superfície de ferramentas do Control Center. O ACP e o bash do harness recebem um ambiente saneado; o Claude Code através do NoSandboxAdapter herda o ambiente do anfitrião.

A execução devolve uma sequência tipada de eventos, que o processador de fluxo persiste como deltas de mensagem, agrega em segmentos de transcrição e converte em eventos de mensagens:

Evento O que transporta
thinking Saída de raciocínio, apresentada em linha
text Saída visível
toolCall Uma invocação de ferramenta, com o respetivo id e argumentos estruturados
toolResult O resultado correspondente, assinalado quando deu erro ou quando é um fluxo parcial
usage Contagens de tokens e custo de uma janela de medição
error Um erro, com o código estruturado do adaptador quando este o comunicou
sandboxViolation O sistema operativo negou uma chamada ao sistema. Só é emitido onde uma sandbox está de facto a envolver o processo — ver a nota acima
debug Diagnóstico em tempo de execução (marcadores de lançamento, decisões das barreiras, insistências do contrato)
done A execução terminou

Não existe deliberadamente qualquer teto de turnos. Uma contagem fixa de iterações mata trabalho longo legítimo (migrações, limpeza de fan-out) e não apanha nada que as proteções abaixo não apanhem mais cedo. Uma execução termina quando:

  • o modelo para por si próprio;
  • uma pessoa a para, ou assume a conversa (o que pausa o harness integrado no seu próximo limite de turno limpo — uma execução do Claude Code, que não tem fronteira segura, é parada em vez disso);
  • o temporizador de silêncio dispara. Sem saída durante o limiar e a sessão é terminada com uma falha silentRun. A predefinição são 15 minutos, a descer para 10 nos modos mais orientados à leitura (revisão e plano); um agente pode substituí-la entre 1 e 240 minutos. O temporizador é armado quando um processo filho comunica o seu PID, por isso cobre a CLI do Claude Code — não o harness integrado, que não gera processos nenhuns;
  • um limite de custo entra em ação — mas apenas para comandos autónomos.

A proteção contra ciclos viciosos não é um terminador: três chamadas de ferramenta idênticas seguidas e o ciclo orienta o agente para mudar de abordagem.

No conjunto, um turno interativo vulgar no harness integrado não tem teto de turnos, limite de custo nem temporizador de silêncio. Termina quando o modelo para ou quando tu o paras. É uma troca deliberada — as alternativas matam todo o trabalho longo legítimo —, mas significa de facto que uma execução interativa sem supervisão não é limitada por nada além do próprio juízo do modelo.

A meio de uma execução, uma mensagem enviada a um agente em execução é colocada em fila como orientação e consumida no limite de turno seguinte, para que possas dar um empurrão a uma execução sem a matar. A orientação, a pausa, os subagentes e o contrato de conclusão são funcionalidades do harness integrado; o Claude Code não tem nenhuma delas.

Cada despacho escreve um AgentRunLog: hora de início e de fim, resumo, contagens de tokens e custo estimado (incluindo o custo agregado a partir dos subagentes), adaptador e modelo, id de processo e caminho do registo, a conversa e qualquer ticket ou execução de pipeline a que pertença, além de dois campos de classificação que transportam a maior parte da verdade.

  • O estado é grosseiro: pending, running, completed, error.
  • A vitalidade é a leitura mais fina: alive, productive, completed, blocked, empty, looping, failed, stalled, dead.
  • A família de erros agrupa as falhas de forma útil: transientUpstream, sandboxInfrastructure, budgetExceeded, processLost, silentRun, unknown.

Fechar a execução publica AgentRunCompleted, e muita coisa depende disso: a agregação de custos do pipeline, a retoma de um passo de pipeline que estava à espera da execução, a conclusão do ticket subjacente, o mapeamento de uma orquestração para um estado terminal, a decisão de continuar ou parar do supervisor de objetivos, o papel de verificador e a avaliação de orçamento posterior à execução. A lista de presença segue-se à parte, ao observar os registos de execução recentes em vez do evento. A notificação «agente finalizado» não consta dessa lista: o evento é disparado quando o stream do processo termina, antes de a resposta ser escrita, pelo que a notificação é o MessageReceived do turno, publicado assim que a mensagem é guardada.

A aplicação do orçamento é uma reação, não um controlo prévio. Quando uma execução termina, o avaliador compara o gasto do agente no mês até à data com o seu teto efetivo (uma política de orçamento associada, se existir; caso contrário, o valor mensal do próprio agente; zero significa ilimitado). Ultrapassar o limiar suave regista um incidente de aviso; esgotar o orçamento regista um incidente rígido e muda o estado do ciclo de vida do agente para paused no organigrama. O despacho continua a aceitar trabalho desse agente. Um gatilho de pipeline BudgetThresholdCrossed pode iniciar trabalho de acompanhamento a partir do mesmo evento.

Cada registo de execução pode transportar linhagem de tentativas — um id de execução mãe, um contador de tentativas e um resumo de continuação. A árvore de execuções da conversa apresenta o número da tentativa quando é diferente de zero. Um «tentar novamente» no chat é um novo despacho, com um registo de execução novo.