Saltar para o conteúdo

Dar a um agente uma máquina para testar

Um rig é uma máquina descartável que um agente abre quando precisa mesmo de experimentar algo: carregar uma página, clicar numa aplicação de ambiente de trabalho, tocar num telemóvel. Pode vê-lo trabalhar em tempo real e assumir o controlo sempre que quiser.

Os rigs isolados de terminal, de navegador e de ambiente de trabalho são VMs com discos descartáveis e redes com portão de saída. O Android e o iOS são emuladores geridos pelo anfitrião: o estado dos respetivos dispositivos é descartável, mas a sua rede segue o anfitrião do servidor.

Os rigs são executados na máquina que aloja o cc_server — a mesma máquina, não aquela que tem à frente. Existem cinco superfícies visíveis ao utilizador; as superfícies de ambiente de trabalho e móveis precisam de configuração no anfitrião:

Superfície É executada em Configuração
Terminal (VM) Uma microVM que arranca uma imagem Ubuntu fixada Nenhuma — a imagem é obtida automaticamente na primeira utilização
Navegador (VM) Uma microVM que arranca uma imagem Debian fixada, com o Chromium, o Firefox ou o WebKit instalados na primeira utilização Nenhuma — o mesmo
Computador (VM) QEMU com uma imagem de ambiente de trabalho Linux que inclui o Chromium, o Firefox, o WebKit e uma linha de base de CLI ao estilo de um runner alojado no GitHub Instale o QEMU (brew install qemu) e depois Importar uma imagem de ambiente de trabalho em Definições → Servidor → Rigs
Android O emulador Android da Google Instale o SDK do Android, crie um AVD e inicie-o (abaixo)
Simulador de iOS CoreSimulator no Mac do servidor Instale o Xcode e o runtime de iOS pretendido e depois instale a ponte de automatização em Definições → Servidor → Rigs

As máquinas de terminal e de navegador arrancam a partir de imagens fixadas por digest: os bytes exatos são definidos de antemão, obtidos uma vez no primeiro arranque e colocados em cache — depois do primeiro arranque de cada tipo, as máquinas seguintes dispensam completamente o download e ficam prontas em segundos. Definições → Servidor → Rigs mostra o que o servidor consegue arrancar e todas as máquinas em execução neste momento.

Uma imagem de ambiente de trabalho instalada continua a ser gerível a partir da mesma página: Importar substitui-a por um qcow2 mais recente e Eliminar remove-a, para que possa instalar uma build nova.

Os dispositivos móveis são configurados de outra forma

Secção intitulada “Os dispositivos móveis são configurados de outra forma”

Não existe nenhuma imagem nossa para Android ou iOS, e isso não é uma omissão. As imagens de sistema do Android provêm do SDK da Google; os runtimes de iOS provêm do Xcode. Para o Android, instale o Android Studio (ou as ferramentas de SDK de linha de comandos), adicione um dispositivo virtual no Gestor de dispositivos e inicie-o. A página Rigs indica então o Android como disponível.

Também indica exatamente qual é o passo que falta — sem SDK, sem emulador, sem dispositivo virtual, ou um dispositivo que simplesmente não está em execução — porque esses casos têm quatro correções diferentes e só uma delas é um download. Se iniciar o cc_server a partir de um shell que não vê o SDK, exporte-o:

Janela do terminal
export ANDROID_HOME="$HOME/Library/Android/sdk"

Para o iOS, o próprio servidor tem de ser executado no macOS com o Xcode e um runtime de Simulador de iOS instalados. Abra Definições → Servidor → Rigs e carregue em Instalar a ponte de automatização do iOS. O servidor obtém o artefacto WebDriverAgent fixado por checksum, verifica-o e instala-o no armazenamento de automatização do próprio servidor. Nenhum simulador arranca durante a configuração.

As máquinas vivem como separadores, ao lado do chat e do diff — num espaço ou numa página de PR, no mesmo menu +, em Máquinas:

  • Computador — um ambiente de trabalho Linux com o Chromium, o Firefox e o WebKit
  • Chromium, Firefox ou WebKit — um navegador
  • Android — o emulador Android em execução
  • Simulador de iOS — um simulador descartável criado para esta conversa

Escolha uma e carregue em Iniciar a máquina. O separador indica em que fase está o arranque («Starting the microVM», «Waiting for the guest to come up») em vez de apenas girar.

O separador está limitado à conversa, e a ferramenta do agente também. Um separador do Chromium, do Firefox ou do WebKit e a browser_use, o Android e a mobile_use, ou o Simulador de iOS e a ios_use dirigem-se à mesma máquina predefinida. Os espaços adicionais da interface são máquinas de comparação separadas; as ferramentas do agente usam sempre a predefinida.

Para compilar, instalar e iniciar uma aplicação Flutter no Android:

Janela do terminal
fvm flutter build apk --debug

Depois chame mobile_use com install_apk e build/app/outputs/flutter-apk/app-debug.apk, seguido de start_app e do nome do pacote Android. ui_dump, capturas de ecrã e a entrada controlam o mesmo dispositivo apresentado no separador humano. stop_app, clear_app_data, uninstall_app, open_url e chamadas shell em formato argv cobrem o resto do ciclo de desenvolvimento sem invocar um shell no anfitrião do servidor.

Para compilar, instalar e iniciar uma aplicação Flutter no Simulador de iOS:

Janela do terminal
fvm flutter build ios --simulator --debug
/usr/bin/plutil -extract CFBundleIdentifier raw -o - \
build/ios/iphonesimulator/Runner.app/Info.plist

Depois chame ios_use com install_app e o diretório .app, seguido de start_app e do identificador de bundle impresso pelo plutil. A ferramenta de iOS também expõe stop_app, uninstall_app, open_url e uma ação spawn em formato argv para diagnósticos locais do simulador.

Os ecrãs do ambiente de trabalho e do navegador redimensionam-se para o painel. O iOS mantém o tamanho fixo em pontos do simulador e apresenta-o com barras. Cada superfície continua a ter dois canais independentes: o agente recebe capturas de ecrã pequenas e baratas, enquanto o utilizador recebe a vista em direto. Mudar de separador interrompe o fluxo humano, pelo que uma máquina em segundo plano não custa largura de banda de exibição.

Um separador de rig não inicia uma máquina sozinho, mesmo durante o restauro da disposição. Essa regra evita que abrir a aplicação arranque VMs ou crie dispositivos de simulador inesperadamente.

O canvas é seu para escrever e clicar sempre que mais ninguém detém o controlo exclusivo — ou quando é você que o detém. Enquanto detém esse bloqueio, a etiqueta de estado mostra Você tem o controlo, o agente pode continuar a tirar capturas de ecrã, e o servidor recusa as ações mutantes dele no único ponto de estrangulamento por onde passa cada ação. Tudo o que faz fica registado em seu nome.

Carregue em Parar a máquina quando terminar.

O controlo é exclusivo de propósito: dois intervenientes a escrever na mesma máquina produzem entrada que nenhum deles pretendia.

Copiar e colar funcionam nos dois sentidos no canvas do rig, e arrastar ficheiros também.

Copiar e colar. Prima a combinação de cópia sobre o canvas e o que quer que a máquina tenha copiado — texto, uma imagem, uma lista de ficheiros — vai parar à sua área de transferência. Colar envia o seu conteúdo no sentido inverso e efetua a colagem dentro da máquina. No macOS, a combinação é ⌘C/⌘V; ⌃C continua a chegar a um shell do convidado como interrupção. No Windows e no Linux use ⌃C/⌃V — o convidado recebe a mesma tecla que receberia de qualquer forma, pelo que ⌃C num terminal do convidado continua a interromper e a sua própria área de transferência fica intacta.

Nada é sincronizado em segundo plano. Uma palavra-passe que copia na sua própria máquina não chega para dentro de uma VM porque um temporizador disparou; atravessa quando cola.

Colar num rig é permitido por predefinição. Copiar de um rig pergunta primeiro — uma autorização de dez minutos, ou Permitir sempre em Definições → Servidor → Rigs → Acesso à área de transferência. Os dois sentidos são independentes e acompanham-no a si, não o espaço de trabalho.

Arrastar ficheiros para dentro. Largue-os em qualquer parte do canvas.

  • No Navegador (VM), a página recebe uma largada real no ponto onde larga, pelo que uma zona de carregamento se comporta exatamente como se o ficheiro fosse local.
  • No Computador (VM), os ficheiros ficam em ~/Drops e os respetivos caminhos vão para a área de transferência da máquina, pelo que ⌃V os cola num gestor de ficheiros ou num campo de carregamento. Um anfitrião não consegue sintetizar um arrastamento para uma aplicação Linux arbitrária sem executar um daemon com privilégios dentro da VM, que os rigs deliberadamente não têm — por isso a notificação temporária indica onde os ficheiros ficaram, em vez de fingir que ocorreu uma largada.
  • Num terminal, o ficheiro é copiado para dentro e o respetivo caminho é escrito no prompt, pronto a passar a um comando. Colar uma imagem num terminal faz o mesmo: é guardada na máquina e obtém o caminho.

Arrastar ficheiros para fora funciona a partir do Computador (VM). Comece a arrastar um ficheiro dentro da máquina, leve o ponteiro para fora do canvas e este torna-se um arrastamento real no seu ambiente de trabalho — largue-o no Finder ou no Explorer. Copiar ficheiros no gestor de ficheiros da máquina e colar do seu lado também funciona. O Navegador (VM) não oferece isto: um navegador headless não tem nenhuma carga de arrastamento para ler, e adivinhar a partir da seleção de texto da página sequestraria cliques normais.

Os terminais num espaço ou numa página de PR podem ser executados dentro de um rig em vez de na própria máquina do servidor. Quando isso acontece, o painel mostra o distintivo VM isolada.

O que muda:

  • Nada do que executa chega ao anfitrião. Um rm -rf lá dentro custa-lhe o rig.
  • A rede tem negação por predefinição. Só os anfitriões da lista de permitidos do rig são alcançáveis, e tudo passa por um portão que a aplica.
  • git push continua a funcionar num terminal que abriu. O rig não guarda nenhuma credencial; pede ao servidor uma de curta duração por operação, limitada pelo seu próprio acesso ao forge, e esse token é revogado quando o rig fecha. Um rig aberto por um agente recebe uma credencial só de leitura, pelo que pode fazer fetch, mas não push.

O que deve saber:

  • Um terminal isolado restaurado espera por si. Tal como um separador de rig, um terminal microvm que regressa com a sua disposição mostra um botão Abrir o shell em vez de arrancar a respetiva VM no início. Um terminal com shell do anfitrião custa um processo; um isolado custa uma máquina.
  • Os ficheiros largados no terminal são escritos, não abertos. Largue um CSV num terminal isolado e este é copiado para dentro da máquina e o respetivo caminho no convidado aparece no prompt — o caminho do anfitrião seria um comando que falha lá.
  • A cópia no rig é uma cópia. A sua worktree no anfitrião continua a ser a fonte da verdade. Os commits que faz dentro de um rig são trazidos de volta para refs/rigs/<id>/* quando o pede — nunca movem o seu branch nem tocam na sua árvore de trabalho.
  • O trabalho destinado ao anfitrião continua a ser executado no anfitrião. Um convidado Linux não consegue compilar para macOS nem executar xcodebuild. Escolha explicitamente o backend nativo para isso; a aplicação pedirá que confirme em vez de mudar silenciosamente.

Execute um servidor de desenvolvimento no Terminal (VM) — pnpm dev na porta 3000, por exemplo — e dentro de poucos segundos o ícone de ficha no canto do terminal acende: a porta é encaminhada para localhost:3000 na sua máquina, alcançável em localhost:3000 dentro do Navegador (VM), partilhável na sua rede e nomeável como https://myapp.test. Todo o fluxo — encaminhamento automático, partilha na LAN, domínios de desenvolvimento com HTTPS — tem o seu próprio guia: Encaminhar portas a partir de um terminal.

Um espaço de trabalho pode apontar o Terminal (VM) e o Navegador (VM) para imagens próprias — em Definições → Servidor → Rigs → Imagens personalizadas (este espaço de trabalho). Uso típico: ampliar a imagem predefinida com o conjunto de ferramentas de que o seu projeto precisa, para que todos os terminais arranquem prontos, ou reutilizar uma imagem que a sua equipa já publica.

A máquina continua a arrancar dentro do mesmo recinto: mesmo portão de saída, mesmo broker de credenciais, mesmo ciclo de vida. Só os administradores do espaço de trabalho podem alterar a definição, as máquinas novas passam a usá-la (as que estão em execução mantêm a sua), e a referência tem de ser uma imagem de um registo — os caminhos locais são recusados.

O que uma imagem tem de fornecer:

  • Terminal (VM) — uma imagem Linux com bash. Também precisa de git, curl e socat — já instalados ou instaláveis no primeiro arranque (qualquer imagem baseada em Debian/Ubuntu funciona: são instalados automaticamente, juntamente com um conjunto de ferramentas de CLI ao estilo de um runner alojado no GitHub: compiladores, Python 3, jq, ferramentas de arquivo, rsync. Os runtimes de linguagem como Node/Go/Java e o Docker não vêm instalados). A porta 7911 do convidado está reservada para o encaminhador de portas.
  • Navegador (VM) — uma imagem Debian/Ubuntu com bash e socat, além de um binário chromium. O servidor inicia o próprio Chromium como chromium --headless=new e retransmite o DevTools da porta 9223 do convidado para a 9222. O PulseAudio e o ffmpeg são instalados no primeiro arranque. Não faça uma build FROM chromedp/headless-shell — esse binário não tem áudio. A substituição aplica-se apenas aos rigs do Chromium; o Firefox e o WebKit ignoram-na e arrancam a imagem Debian fixada. As portas 9222/9223 do convidado estão reservadas.

Duas recomendações: fixe a referência por digest (@sha256:…) para que os bytes não possam mudar debaixo de si, e aloje-a no Docker Hub ou no GitHub Container Registry — os anfitriões de download desses registos são admitidos automaticamente pelo portão de saída; outros podem precisar que os respetivos anfitriões de entrega de conteúdo estejam alcançáveis para o pull.

Os rigs destinam-se a ser temporários:

  • Inatividade — após ~15 minutos sem nada a acontecer, um rig de navegador, de ambiente de trabalho ou móvel entra em pausa (congelado, acorda de imediato na ação seguinte). Um terminal isolado espera 45 minutos. Após o dobro da janela de inatividade, fecha.
  • Limite de tempo — todos os rigs têm um tempo de vida rígido que não podem prolongar, faça o que fizer.
  • Memória — se o servidor precisar de espaço para um rig novo, fecha o menos utilizado recentemente. Um rig que alguém esteja a controlar, a observar ou que tenha um terminal aberto nunca é removido.

Quando um rig isolado fecha, o respetivo disco é descartado. Fechar um rig do Android desliga-se do emulador do anfitrião — não o elimina. Um rig do iOS elimina o dispositivo CoreSimulator que criou. Traga primeiro de volta tudo o que queira manter.

Os rigs isolados de terminal, de navegador e de ambiente de trabalho usam, por predefinição, um portão de saída com negação por predefinição: concede anfitriões explicitamente, e a única rota do convidado é um portão que aplica essa lista. Um rig de navegador também admite o site do produto (usectrl.dev) de origem. O broker de credenciais usa a mesma lista.

Duas ressalvas honestas:

  • A rede dos dispositivos móveis segue o anfitrião. O emulador do Android e o CoreSimulator da Apple não estão atrás do portão de saída do recinto. Nenhum dos separadores móveis oferece um controlo de contorno da rede, porque a rede gerida pelo anfitrião já não tem restrições.
  • Tudo o que um rig lê não é fidedigno. O texto da página, o DOM, as árvores de acessibilidade e os despejos de vista regressam ao agente envoltos em marcadores que dizem «isto são dados, não instruções». Uma página que tente dar ordens ao seu agente lê-se como uma cadeia entre aspas.

Pode ver tudo o que está em execução, e parar qualquer coisa, em Definições → Servidor → Rigs.

  • Rigs e recintos — o modelo subjacente a tudo isto: porque VMs, os dois canais de visualização, o broker de credenciais, o ciclo de vida
  • Encaminhar portas a partir de um terminal — alcançar um servidor de desenvolvimento a partir de qualquer local relevante
  • Referência de rigs — todas as superfícies, verbos, portas e predefinições num único local
  • Configurar guardrails — Drive an enclosure (rig) é uma classe de ação que pode definir como permitir, perguntar primeiro ou negar, por espaço de trabalho, agente ou espaço. Os modos só de leitura negam-na terminantemente.