Hermes Passa a Entregar os Ficheiros que o Agente Cria Dentro de Sandboxes Remotos


Imaginemos uma sexta-feira à noite: colocou as mãos do Hermes dentro de um sandbox remoto — um ambiente cloud da Modal, ou uma dev box SSH da empresa — porque quer um isolamento limpo que nunca toca nos ficheiros do seu portátil. O agente termina o trabalho, produz um gráfico, um relatório, uma captura de ecrã de uma página web dentro desse sandbox e anexa, todo satisfeito, o caminho do ficheiro à sua resposta. A sua janela de chat não mostra nada. O único vestígio é uma linha de log: “Skipping unsafe MEDIA directive path.” O ficheiro existe — simplesmente não consegue chegar até si.

Porque é que os ficheiros costumavam desaparecer

Para perceber isto, primeiro é preciso saber como o Hermes lhe entrega ficheiros. O agente escreve uma tag MEDIA:<path> na resposta; o gateway vê-a, retira o ficheiro e envia-o para o seu chat como imagem ou anexo. Essa validação de caminhos sempre foi apenas no host, por design — a entrega de media nunca pode tornar-se um canal para ler ficheiros arbitrários do sistema, por isso ~/.ssh, os diretórios de sistema e os próprios repositórios de credenciais do Hermes estão numa denylist e são sempre recusados.

O problema é exatamente essa parte de “apenas no host”. Quando o seu terminal backend é ssh, Modal, Daytona, Singularity ou um sandbox da Vercel, os comandos de terminal do agente correm noutra máquina — noutro sistema de ficheiros. O ficheiro por detrás de MEDIA: simplesmente não está no host do gateway, a validação falha e o anexo é descartado como “caminho inseguro”. O ficheiro foi gerado sem qualquer problema; o gateway é que não o conseguia alcançar.

A correção: ir ao sandbox e trazer o ficheiro de volta

O PR #103600, fundido a 5 de setembro de 2026 (a metade de saída da issue #466), muda isso. A ideia é direta: quando a validação no host falha, mas a sessão atual está genuinamente a correr dentro de um sandbox remoto, o gateway passa a trazer o ficheiro de volta através do exec channel e a submetê-lo ao fluxo de entrega normal.

Funciona em três camadas:

  • Transport (tools/environments/base.py): todos os backends de ambiente ganharam um fetch_file / fetch_realpath uniforme — o ficheiro é codificado em base64 e enviado de volta pelo exec channel, com limite de tamanho dentro do sandbox (head -c max+1, o mesmo truque que tools.image_source usa para que um stream infinito como /dev/zero não possa inundar a memória do host), com marcadores de payload que isolam o ruído da shell de login.
  • Trigger (novo gateway/media_fetch.py, ~120 linhas): só dispara quando um backend remoto está ativo e a validação no host já falhou — um backend local nunca segue este caminho.
  • Hook (gateway/platforms/base.py::_validated_delivery_path): uma adição de três linhas, o único ponto de estrangulamento partilhado por todos os pontos de filtragem de MEDIA — uma correção, eficaz em todo o lado.

Limites de segurança: não é um backdoor para contornar a denylist

Ir buscar ficheiros a um sandbox remoto é exatamente o tipo de funcionalidade que se pode tornar numa bypass da denylist, por isso o caminho é verificado duas vezes: primeiro contra a mesma denylist do host (prefixos de sistema, diretórios da classe ~/.ssh, repositórios de credenciais do Hermes), antes de qualquer byte se mover; e depois novamente, quando readlink -f resolve o caminho real — um symlink que aponte para um ficheiro de credenciais é recusado de imediato, sem que um único byte seja transferido. Os ficheiros que passam são copiados para cache/documents/ (que é, ela própria, uma raiz de entrega na allowlist) e depois validados e entregues exatamente como qualquer ficheiro do host. O limite é 50MB, o mesmo do limite de upload de cada plataforma.

Quer o comportamento antigo de volta? Em strict mode, com HERMES_MEDIA_DELIVERY_STRICT, os ficheiros remotos continuam a nunca ser obtidos — uma cópia obtida iria parar numa raiz na allowlist e poderia contornar o recency gate que o strict mode existe para garantir, por isso o strict mode mantém tudo como estava.

Que configurações beneficiam

Qualquer terminal backend remoto — ssh, Modal, Daytona, Singularity, sandbox Vercel — entrega agora os ficheiros que o agente aí cria e referencia com uma tag MEDIA:: capturas de ecrã de um scraper a correr no sandbox, gráficos de um script de análise de dados, relatórios escritos no fim de uma tarefa longa. Tudo aquilo a que pediu ao agente para “guardar e enviar”. Os backends locais comportam-se exatamente como antes — nunca precisaram de ir buscar nada.

Uma fronteira honesta: os backends que conseguem reportar o seu diretório home remoto (_remote_home, por ex. ssh, Daytona, Vercel) têm suporte total; Modal, Singularity e Docker sem mounts do host não conseguem confirmar o home remoto, por isso mantêm a denylist conservadora por componente — nesses casos, os ficheiros sob prefixos de sistema como /root continuam a não ser obtidos por predefinição, a menos que o ambiente defina explicitamente _remote_home para optar por essa via.

O que ainda falta

Esta alteração implementa apenas a metade “de saída” da #466. O PR exclui deliberadamente: uma ferramenta core autónoma send_file (a tag MEDIA: existente é a interface — degrau 1 da footprint ladder), transportes nativos por backend e a injeção inbound de anexos nos sandboxes (ainda em aberto na #466). Estas seguem a footprint ladder e são lançadas de forma incremental, em vez de todas de uma vez.

Como a obter

Não há comando novo nem configuração nova — é uma correção de comportamento do gateway e ativa-se no upgrade. A alteração foi fundida no main (2026-09-05) e ainda não está incluída em nenhuma release tag; execute uma instalação dev/main para experimentar já, ou simplesmente hermes update quando sair a próxima release. Uma forma rápida de verificar depois: dentro de um sandbox remoto, peça ao agente para gerar uma imagem e “enviá-la para si” — deve chegar; depois coloque um symlink a apontar para ~/.ssh e confirme que continua a ser recusado. As duas verificações a fazer o seu trabalho.

Para saber mais sobre sandboxes e backends, consulte os nossos guias anteriores sobre contentores Docker partilhados e backends de terminal plugáveis; o ritmo das releases está na página de releases.