Queres que o Hermes use um sandbox de cloud específico como terminal? Agora escreves um plugin — sem esperar por alterações no core


Sempre quiseste que o Hermes corresse comandos de terminal num sandbox de cloud específico — código mais seguro, ambientes mais limpos, e sem mais conflitos de dependências locais. Depois abres a documentação e vês apenas os backends integrados listados. Aquele que queres implica esperar que os mantenedores fundam o código do fornecedor no repositório core, ou manter o teu próprio fork para sempre. O PR #94400, fundido a 25 de agosto, põe fim a essa espera: os backends de terminal são agora um subsistema pluggable. Um sandbox de cloud de terceiros pode registar-se como valor de terminal.backend através de um plugin autónomo — sem alterações no core, sem fork.

Porque é que esta era a “última grande peça”

Em todo o ecossistema de ferramentas do Hermes, a geração de imagem/vídeo, o web scraping, o browser, a memória, o TTS/STT e os fornecedores de modelos suportam integração no estilo plugin desde há muito — exceto os backends de terminal. Os terminais tocam em demasiados pontos sensíveis: aprovações, caminhos de contentores, caches, remoção de secrets — o maior raio de impacto de qualquer subsistema. O PR #94400 fecha essa lacuna: os fornecedores de sandbox podem agora escrever um plugin e deixar os utilizadores definir terminal.backend: <your-backend-name> diretamente.

Há um primeiro consumidor real por detrás disto: o backend de cloud-sandbox Sprites (originalmente #93523) foi o primeiro a migrar para esta interface — passou para um repositório de plugin privado e autónomo, em vez de viver no core.

Como é um plugin: uma ABC + uma função de registo

O mecanismo centra-se em dois ficheiros novos: agent/terminal_env_provider.py define a classe base abstrata TerminalEnvironmentProvider, e agent/terminal_env_registry.py é um registo thread-safe. O que um autor de plugin faz (o exemplo mínimo do guia oficial de developer, developer-guide/terminal-environment-plugin.md):

# ~/.hermes/plugins/acmebox/__init__.py
from agent.terminal_env_provider import TerminalEnvironmentProvider

class AcmeBoxEnvironment:
    """Tem de satisfazer o contrato duck-typed da BaseEnvironment."""
    def __init__(self, cwd, timeout, task_id):
        self.cwd, self.timeout, self.task_id = cwd, timeout, task_id

    def execute(self, command, timeout=None, **kwargs):
        ...  # executa o comando no sandbox
        return {"output": "...", "exit_code": 0}

    def cleanup(self):
        ...  # encerra / desliga

class AcmeBoxProvider(TerminalEnvironmentProvider):
    name = "acmebox"
    display_name = "AcmeBox"
    is_remote = True       # os comandos não correm no host
    is_container = True    # semântica de path/cwd estilo contentor

    @property
    def cache_path_base(self):
        return "~/.hermes"  # onde os ficheiros de cache sincronizados vão parar, ou None

    @property
    def strip_env_keys(self):
        return frozenset({"ACMEBOX_TOKEN"})  # secrets removidos dos subprocessos

    def create_environment(self, *, cwd, timeout, task_id="default",
                           image=None, container_config=None, **kwargs):
        return AcmeBoxEnvironment(cwd, timeout, task_id)

def register(ctx):
    ctx.register_terminal_environment_provider(AcmeBoxProvider())

O diretório do plugin também traz um plugin.yaml (name, version, kind: backend). Depois ativa-o e seleciona-o:

hermes plugins enable acmebox
hermes config set terminal.backend acmebox

Os nomes de backends integrados (local, docker, singularity, modal, daytona, vercel_sandbox, ssh) estão reservados — os plugins alargam o conjunto, nunca fazem sombra a um integrado.

Seis flags de classificação que eliminam a classe de bugs “o novo backend esqueceu-se de um sítio”

No passado, adicionar um backend significava sincronizar a lógica de decisão por sete ou oito sítios no código — que backends são remotos, quais são contentores, quais saltam aprovações, como se traduzem os caminhos de cache — e falhar um era um bug difícil de encontrar (a issue #30112 exigiu uma varredura de sete sítios). O novo design declara tudo isto:

  • is_remote: os comandos correm noutro lugar que não o host. Suprime as dicas de OS/home/cwd do host, a sonda do ambiente Python do host e o tratamento de skills com noção de remoto;
  • is_container: comporta-se como um contentor/sandbox com o seu próprio filesystem — a configuração de recursos do contentor passa, cwds com aparência de host são saneados, as ferramentas de ficheiros usam resolução de caminhos do contentor;
  • skip_container_guards: o sandbox é suficientemente isolado para que os pedidos de aprovação de comandos perigosos sejam saltados (o padrão é is_container; backends que consigam montar caminhos do host devem substituir por False);
  • cache_path_base: onde os ficheiros ~/.hermes/cache sincronizados automaticamente vão parar dentro do backend (por exemplo, ~/.hermes ou /root/.hermes), ou None quando não há nada a traduzir;
  • strip_env_keys: variáveis de ambiente com credenciais pertencentes a este backend (tokens de API do fornecedor), removidas de todos os subprocessos que o agente lança para que comandos escritos pelo modelo nunca as consigam ler;
  • session_isolated_when_nonpersistent: o modo não persistente dá a cada sessão a sua própria identidade de sandbox, em vez de partilhar uma.

Onde o plugin aparece depois de registado

Um backend registado não é apenas um valor no ficheiro de configuração — todas as superfícies o reconhecem automaticamente:

  • O seletor de backends do hermes setup mostra a nova opção com configuração guiada pelo fornecedor;
  • O hermes status / hermes doctor listam o backend do plugin e o seu estado de saúde;
  • O seletor de backends de terminal do dashboard suporta backends de plugin e recalcula por pedido — um plugin instalado a meio de uma sessão aparece imediatamente.

O guia oficial de developer percorre a escrita de um backend plugin a partir do zero.

O que isto significa para os utilizadores comuns

Se só usas os backends integrados (terminal local, Docker, Modal, SSH), esta alteração é invisível em termos de comportamento — é uma porta arquitetural, não um interruptor de comportamento. O impacto no ecossistema é o que interessa: quando um fornecedor de sandbox diz “suporta Hermes”, passa a significar “instala o plugin”, não “espera por um merge no core”; a qualidade do plugin é responsabilidade do fornecedor, e o hermes doctor diz-te se está saudável. Para o básico sobre plugins, consulta a referência de comandos hermes plugins; para o mecanismo de entry-point por detrás dos fornecedores instalados via pip, o nosso guia de plugin de model provider via pip cobre a linhagem. A seleção de backends no dia a dia está documentada no guia de instalação.

Resumo

Backends de terminal pluggable transformam “fazer o Hermes usar o meu sandbox de cloud” de “implorar por um merge no core” em “escrever um plugin, declarar seis flags, registar, pronto”. É a última peça do ecossistema de ferramentas do Hermes a tornar-se plugin-native — os backends de terceiros estão agora desacoplados do core, com a política de segurança aplicada uniformemente através de flags declarativas.