v0.21.5

Hermes Agent v0.21.5


Visão Geral

v0.21.5 — mais uma tag que existe para consumidores downstream. Publicada em 24 de setembro de 2026. Desde a v0.21.4: 1.610 commits não-merge · 4.828 arquivos alterados (+164.132 / −149.440) · 460 PRs mesclados · 475 issues fechadas, medidos no commit f97608f178d1ffeca59860195ab7da295f7c8e5f.

A tag existe pelo mesmo motivo que a v0.21.4: as imagens Docker, o Hermes Cloud e as implantações hospedadas são todos construídos a partir da tag de release mais recente, então as correções desta janela precisam chegar a uma versão estável antes que os usuários de nuvem possam recebê-las. O corpo da release diz isso sem rodeios — o texto curado completo fica adiado para a v0.22.0, que vai documentar tudo a partir da v0.21.0: destaques, áreas de funcionalidade e créditos completos de contribuidores. Nada desta janela é deixado de fora.

Até lá, esta página registra para quem a tag existe e as mudanças da janela que já estão rodando na sua máquina.


Destaques

1. O Desktop ganha catálogos completos de francês, alemão e espanhol, além de uma configuração de direção do texto

O Desktop agora traz catálogos de interface completos para francês, alemão e espanhol, listados em Settings → Appearance → Language. Os três catálogos traduzem todas as chaves de en.ts, incluindo todos os rótulos e descrições de configurações de defineFieldCopy e a rotação de intro apenas de exibição (intro-{fr,de,es}.ts). Eles se registram como overlays defineLocale(), assim como ja, ar e ru, então uma chave adicionada depois ao inglês cai de volta no inglês em vez de quebrar o typecheck de todos os contribuidores. O backend já traz locales/{fr,de,es}.yaml; display.language: fr|de|es e aliases regionais como fr-CA, de-AT e es-419 agora resolvem para o catálogo correspondente em vez de cair de volta no inglês. O francês usa vous, o alemão usa Sie e o espanhol usa o imperativo neutro tú. Nomes próprios e identificadores técnicos (Hermes, MCP, API, OAuth, IDs de modelo, variáveis de ambiente, nomes de arquivo) permanecem sem tradução. PRs #120829.

Ao lado disso vem Appearance → Chat display → Text direction, com três opções: Auto / Right-to-left / Left-to-right. Até agora cada bloco de prosa do chat e cada linha do composer escolhia a sua direção base pelo primeiro caractere forte (UAX#9 plaintext), o que não consegue distinguir um parágrafo em árabe que começa com um nome latino de um parágrafo em inglês citando árabe. Auto é exatamente o comportamento antigo — nenhum atributo novo, nenhuma chave de armazenamento; escolher RTL ou LTR aplica um único dir à prosa do chat e aos dois composers, incluindo todas as linhas de um rascunho com várias linhas. O código permanece LTR (blocos de código, código inline e KaTeX continuam isolados) e a moldura do app (barra lateral, barra de ferramentas, botões do composer) não vira. É só apresentação: nenhum caractere de controle bidi entra em rascunhos, mensagens enviadas ou texto copiado. A preferência pertence ao renderer, não é uma chave do config.yaml. PRs #120822.

2. Entregas de webhook podem ser espelhadas na sessão do chat de destino

Por padrão uma entrega é fire-and-forget: cada evento roda na própria sessão, então responder “então ele saiu?” naquele chat recebe de volta “a quem você está se referindo?”. Uma rota agora pode aderir com mirror_to_session: true (ou hermes webhook subscribe … --mirror-to-session), e depois de um envio bem-sucedido o texto entregue é anexado à sessão do chat de destino como [Webhook delivery: <route>] mais a mensagem, na forma de um turno user rotulado com autoridade de usuário — o mesmo caminho e a mesma convenção de papel dos briefs de cron continuáveis (gateway.mirror.mirror_to_session). Desligado por padrão; só um booleano true de verdade adere. O espelhamento roda dentro de _profile_scope(profile), então uma rota /p/<profile>/ grava no state.db daquele profile e nunca no de outro. É best-effort: nunca faz a entrega falhar e é pulado quando o chat ainda não tem uma sessão de gateway. Numa rota deliver_only o texto espelhado é o payload renderizado bruto, então ative isso apenas para fontes em que você confia que fiquem na sua conversa. PRs #120825.

3. O Bot Screen chega a imagens hospedadas por meio das tags -desktop

Implantações hospedadas e imutáveis agora ganham o Bot Screen baixando uma tag de imagem -desktop. A imagem publicada sai sem Xvnc/Xfce e não consegue instalar em tempo de execução (hermes sem privilégios, sem sudo, /opt/hermes selado), então a camada da imagem é o único caminho de entrega. :latest / :main / :v* são a imagem que já são hoje; :latest-desktop / :main-desktop / :v*-desktop adicionam os pacotes e o Chromium com interface do Playwright. Um manifesto por variante, então uma falha na publicação do desktop não pode pular o :latest do slim. Contêineres não têm logind, então XDG_RUNTIME_DIR=/tmp/hermes-runtime é criado com 0700 como hermes na inicialização — o antigo fallback $HOME/.cache caía no volume compartilhado /opt/data, onde duas instâncias disputavam um único lock de display — e um diretório pertencente a outro usuário ou com symlink é recusado em vez de receber chown. PRs #120914; o doc do recurso é website/docs/user-guide/features/bot-screen.md.

4. Adicione um modelo por slug em todos os seletores de modelo

O menu de modelos do composer, o diálogo de troca de modelo, Settings → Model e a lista de edição de modelos agora todos podem adicionar um modelo por slug: uma nova linha de rodapé Add custom model… transforma a caixa de busca em entrada de slug, oferecendo uma linha por provider configurado conforme você digita, e o slug memorizado permanece na lista como uma linha normal com um × de remoção. PRs #120693.

5. Vozes locais param de recarregar a cada ativação

tts.keep_warm_seconds (padrão 60) é novo: depois que o último lease é liberado, o descarregamento espera esse tempo, e qualquer toggle que reative a fala dentro da janela o cancela e reutiliza o modelo carregado. 0 descarrega imediatamente. Isso importa principalmente para conversas de voz apenas por ativação, que terminam logo depois do aquecimento de ~2s do Piper — a voz costumava ser descartada milissegundos depois de carregar, então cada ativação pagava o recarregamento completo. PRs #121080.

6. O loop de voz do desktop passa a ler a sua configuração

O Read Aloud não fala mais placeholders em inglês como “code block omitted” e “link”, e não descarta mais tabelas Markdown: blocos de código e URLs ficam mudos, tokens de link de arquivo MEDIA: nunca chegam à voz (a pontuação logo depois de um token inline é mantida), dois-pontos no fim da linha, deixados pendurados por um bloco removido, viram um ponto final, e as tabelas falam a sua linha de cabeçalho (“Item, Value, Notes.”) pulando as linhas de corpo. PRs #120752. O spoken stop agora lê voice.stop_phrases (padrão ["stop"]) — antes ele casava com uma lista fixa em inglês, então um usuário russo dizendo “отбой” conforme o aviso instruía tinha isso enviado ao agent como prompt — e a fala inteira precisa ser igual a uma frase, com [] desativando o spoken stop. A reprodução com barge-in não usa mais um gatilho fixo de 0.14, que ficava acima do nível de fala de um headset Bluetooth HFP enquanto uma resposta toca, e é por isso que falar por cima da resposta nunca a interrompia; agora ela usa o já existente voice.barge_in_threshold_multiplier (padrão 3.0). PRs #120751.

7. Atalhos de voz por tecla de função são remapeáveis

O ditado pontual do composer agora é uma ação de teclado composer.dictate sem binding, separada da conversa por voz, reutilizando o caminho de captura canônico do Desktop para teclas F, Caps Lock, Delete, Space e combinações de modificadores. O campo obsoleto voice.record_key do Desktop foi removido, com uma nota de que a configuração continua apenas para CLI/TUI. A arbitragem do Electron faz com que um F12 atribuído chegue ao renderer enquanto um F12 não atribuído mantém o comportamento do DevTools. PRs #120928. Na mesma janela, os fluxos de trabalho por tecla de função no macOS foram corrigidos: o parser da TUI mantém as sequências de terminal F1–F12 intactas (incluindo os caminhos de protocolo com tecla modificada), e Ctrl+R foi adicionado como fallback portátil do F7 para o dock de trabalho ao vivo na TUI e no CLI clássico. PRs #120666.

8. Uma leva de falhas que só atingiam Windows localizados

Quatro problemas independentes, exclusivos do Windows:

  • O crash do nome de fuso. O Windows devolve nomes de fuso na code page ANSI (Paris, Madrid (heure d'été) como bytes cp1252). Quando LC_CTYPE é UTF-8, esses bytes são decodificados com surrogateescape, então tzname() acaba guardando surrogates soltos; datetime.strftime insere tzname() no formato como UTF-8, então %Z levanta UnicodeEncodeError dentro do strftime — antes de existir qualquer string que a passada existente _sanitize_surrogates pudesse limpar. O system prompt é reconstruído no início de cada conversa e a cada compactação, então a falha voltava sempre. O novo hermes_time.safe_strftime() é byte a byte idêntico ao strftime em locales saudáveis (o invariante do cache de prefixo se mantém) e, caso contrário, decodifica os bytes escapados como surrogate pela code page ANSI. PRs #120748.
  • Decodificação de processos filhos no Windows chinês. O _readerthread de subprocess.communicate() no Windows decodifica a saída do filho com subprocess._text_encoding() — locale.getencoding(), cp936/GBK no Windows chinês — sempre que uma captura passa text=True sem encoding=. Os filhos em questão escrevem UTF-8, então qualquer byte ilegal em GBK levanta UnicodeDecodeError naquela thread, que o threading.excepthook do processo serve imprime como uma linha [gateway-crash]. O hermes_cli/web_routers/files.py::_fs_git_branch era um desses (os seus kwargs ficam num literal de dict, então a regra baseada em linha de text=True nunca o pegava) e o Desktop faz polling dele continuamente. PRs #120749.
  • Caminhos absolutos do Windows. C:\...\report.html e caminhos UNC \\server\share\... não eram reconhecidos como caminhos (então nenhuma tag de artefato aparecia) nem eram deixados em paz pelo fallback do renderer, que tratava tudo que não começasse com / como relativo e juntava ao cwd, produzindo caminhos como /repo/C:\...; o rótulo da pré-visualização então interpretava C: como esquema de URL. O novo isWindowsAbsolutePath aceita uma letra de unidade com qualquer uma das barras e um prefixo UNC. PRs #121074.
  • A sonda de boot em cold start. Num cold start do Windows o backend local responde HTTP e depois o seu event loop trava por 12–28s enquanto o GIL fica retido importando os módulos de plataforma do gateway. A sonda WebSocket de boot desistia depois de 10s fixos, travando um status de falha de boot, derrubando o processo filho e entrando na cascata “Ignoring stale Hermes backend exit (1)”. Um backend que este app gerou agora continua esperando além do orçamento-base de 10s enquanto o filho estiver vivo, até um teto de 90s — o mesmo orçamento que a etapa de anúncio de porta já concede a um cold start. O sinal de progresso é a vivacidade, não a recência da saída, porque a trava é silenciosa. Gateways remotos, o botão “Test remote” e a conexão ao backend host mantêm o orçamento fixo de 10s. PRs #120750.

Melhorias

  • A leva do SDK de plugins do Desktop (API de rascunho do composer, slots de lista de sessões e de decoração de linhas, preferências de navegação da barra lateral, rótulos de pílulas de modelo, pontes tipadas de settings/skills/toolsets/profiles, uma primitiva de embed em sandbox, um slot de configurações de aparência, uma ponte pública de eventos para backends de plugins) chegou inteira nesta janela; o texto planejado para ela também fica adiado.
  • A página Connectors substituiu a aba MCP, com “Connect now” para os servidores MCP de um plugin recém-instalado, e as tools e skills dos plugins instalados passam a funcionar em todos os chats abertos; o onboarding oferece plugins do catálogo ao lado dos conectores.
  • O Kanban recebeu um passe de design: um modal de ticket em duas colunas e texto de tarefa em markdown.
  • A janela também traz uma longa sequência de trabalho de performance nos caminhos críticos, cobrindo carregamento de configuração, o registro de tools, o tratamento de mensagens do gateway e o seletor de modelos.

Atualização

hermes update                 # instalações via git
# ou rode de novo o one-liner do instalador

Docker / Hermes Cloud: as imagens são construídas a partir desta tag, nousresearch/hermes-agent:v2026.9.24.

Changelog completo: v2026.9.21…v2026.9.24

Mapeamento de versão: a tag é baseada em data (v2026.9.24) e a versão semântica é a v0.21.5 — a mesma release.

← Hermes Agent Changelog