Hermes Corrigiu 4 Bugs Sorrateiros em Um Dia: Anexos, API Keys, Atualizações, Busca


Você já teve aquele momento de “algo não está certo”? Você pede ao Hermes para enviar um arquivo para o Telegram, ele responde “enviado” — mas o anexo nunca aparece. Ou você roda vários profiles na mesma máquina, troca de modelo e percebe que as credenciais em uso não parecem ser as suas. Ou você pesquisa no histórico de sessões uma frase que com certeza disse, e não recebe nada de volta. Isso não é impressão sua — são quatro bugs profundos do Hermes Agent, todos corrigidos em 9 de agosto de 2026. Este post detalha cada um: como parecia, por que acontecia e como a correção funciona.

Bug 1: Anexos que desaparecem silenciosamente — dizia “enviado”, mas nada chegou

O caso: Você pede ao Hermes no Telegram para gerar um relatório em PDF. Ele responde “relatório gerado, enviando agora.” Mas seu chat mostra apenas uma linha estranha de texto: MEDIA:/path/to/report.pdf — nenhum arquivo, apenas o caminho literal. Pior, às vezes nem isso: ele registra “entrega confirmada” e não acontece nada.

Causa raiz: O bug vivia no caminho de entrega enfileirada (queued delivery). Quando uma resposta precisava ser enfileirada (enquanto a rodada anterior ainda estava em execução, durante rebaixamentos de subagent/compressão, rajadas de fotos ou no modo de fila), a resposta da primeira rodada saía por um caminho lateral que ignorava completamente o tratamento de MEDIA: respostas não-streamed eram enviadas via adapter.send() cru, com a tag literal MEDIA: como texto e sem arquivo; respostas já streamed registravam “entrega confirmada” e descartavam silenciosamente os anexos. O Hermes dizia que um arquivo havia sido produzido — o arquivo nunca chegava.

A correção: Uma nova função _deliver_queued_first_response() agora trata as entregas enfileiradas de forma uniforme: ela separa o texto dos anexos usando a maquinaria existente de extract_media + _deliver_media_from_response (preservando o filtro de segurança de caminhos) e roteia tudo pelo fluxo padrão de envio de anexos. Há também uma proteção sensata: se a primeira rodada de fato falhou, ela entrega o texto de erro normalizado, mas nunca faz upload de anexos — sem mais disfarçar falhas como sucessos.

O que você deve saber: Se você já recebeu uma linha de texto MEDIA: ou um anexo ausente no Telegram, no Discord ou em qualquer plataforma de gateway, era isso. Após a correção, os anexos chegam corretamente; antes de atualizar, você pode recorrer ao navegador de arquivos ou ao web_extract para inspecionar os arquivos produzidos.

Bug 2: API Keys cruzando profiles — trocar de modelo lia a chave de outro profile

O caso: Você roda vários profiles na mesma máquina (digamos, trabalho e pessoal), cada um com suas próprias API keys do provedor de modelo. Um dia você muda para o seu profile pessoal e abre o seletor de modelos — a lista de “provedores autenticados” está mostrando provedores autenticados com as chaves do seu profile de trabalho. Você estava a um clique de enviar uma requisição com a chave errada.

Causa raiz: Com profiles multiplexados, as leituras de credenciais durante a troca de modelo ignoravam o escopo de segredos de cada profile. Dois pontos foram afetados: a listagem “quais provedores estão autenticados” do seletor e a resolução real de chaves do switch_model — esta última lia cruamente o ambiente do processo (expansão de ${VAR} e fallback de key_env) e entregava o resultado à resolução em runtime como uma API Key explícita. Um profile podia, portanto, ver — ou adotar — as API keys de outro profile.

A correção: Um novo helper _scoped_key_env() roteia ambas as leituras por agent.secret_scope.get_secret. Com a multiplexação desligada, o comportamento é byte a byte idêntico ao os.getenv (usuários de profile único não são afetados). Com ela ligada, as leituras ficam estritamente confinadas ao escopo de segredos do profile atual. A decisão de design central: fail-closed. Se um UnscopedSecretError for levantado, ele gera erro em vez de cair de volta para as variáveis de ambiente — chaves nunca vazam silenciosamente entre profiles.

O que você deve saber: Este é o único problema type/security dos quatro — trata-se de isolamento de chaves, então usuários com vários profiles devem atualizar o quanto antes. O comportamento com profile único está completamente inalterado.

Bug 3: Processos órfãos após atualizações — atualizações do desktop no Windows travadas

O caso: Você está no Windows, usando o aplicativo desktop do Hermes. Você clica em atualizar, mas a nova versão não inicia — os processos antigos ainda seguram o ambiente virtual, os arquivos estão bloqueados e a atualização continua falhando. O Gerenciador de Tarefas mostra um cemitério de processos de backend “sem pai” que se recusam a morrer.

Causa raiz: Durante atualizações do desktop, releaseBackendLock() enviava SIGTERM ao backend principal antes de forceKillProcessTree() ser executado. No Windows essa ordem é fatal: se o launcher sai antes do taskkill /T executar, o Windows não consegue mais enumerar seus descendentes — os processos filhos sobrevivem, segurando o venv, e se tornam órfãos.

A correção: Uma nova stopBackendTreesForUpdate() mata a árvore pela raiz viva primeiro (sem sinalização prévia) e depois cuida do teardown do pool. A classificação de órfãos também ficou ciente da árvore: as raízes órfãs do scanner são retornadas junto com seus descendentes (incluindo o worker do interpretador gerenciado por uv, re-executado, cujo pai vivo é a própria raiz órfã) — o taskkill /T então recolhe a subárvore inteira de uma vez. Backends com um pai genuinamente vivo são deixados em paz.

O que você deve saber: Esta correção afeta apenas o fluxo de atualização do desktop no Windows. Usuários de Linux/macOS não são afetados; se você já passou por “atualização travada / processos sobraram” no Windows, isso deve melhorar drasticamente.

Bug 4: Busca falhando silenciosamente — consultas do dia a dia retornam nada

O caso: Você pesquisa no histórico de sessões por gateway/run.py — o arquivo que você com certeza discutiu — e recebe “nenhum resultado.” Você tenta it's, user@host, 50%. Todos vazios. Você começa a duvidar da própria memória. As palavras estavam lá; a busca estava quebrada.

Causa raiz: A busca de sessões usa a busca full-text FTS5 do SQLite, mas o sanitizador de consultas só removia seis caracteres (+{}():"^). A gramática do FTS5 rejeita muitos outros — apóstrofos, barras, @, vírgulas, pontos de interrogação, sinais de igual, ponto e vírgula, exclamações, pipes, tils, cerquilhas, cifrões, colchetes, colchetes angulares, barras invertidas — e qualquer um deles chegando cru ao MATCH levantava um OperationalError, que o local da consulta engolia transformando em zero resultados. Você não estava pesquisando “nada”; a consulta estava travando.

A correção: A classe de remoção do sanitizador foi reconstruída (via re.escape, que também corrigiu a perda de barras invertidas literais) para cobrir o conjunto completo de rejeições, com casos especiais inteligentes: frases exatas entre aspas ("exact phrase") sobrevivem via extração de placeholders, termos com pontos ou hífens não são tocados, e % só é removido em consultas não-CJK — porque % é um caractere reservado para o fallback LIKE de CJK, e consultas CJK nunca atingem o caminho de erro do FTS5 de qualquer forma.

O que você deve saber: Após a correção, it's, gateway/run.py, user@host e 50% todos fazem parse e casam corretamente; consultas CJK não são afetadas. Se a busca do Hermes já pareceu instável para você, provavelmente era por causa deste bug.

Resumo: um dia de merge, quatro lições

Bug Sintoma Severidade Afeta
Anexos que desaparecem Texto MEDIA: literal / arquivos descartados silenciosamente Funcional Todas as plataformas de gateway (Telegram, Discord, …)
Vazamento de API keys entre profiles Troca de modelo lê a chave de outro profile Segurança Usuários com profiles multiplexados
Órfãos de atualização Processos antigos bloqueiam o venv após atualizações no Windows Funcional Desktop no Windows
Falhas silenciosas de busca Consultas com caracteres especiais retornam vazio Funcional Todos

O fio condutor dos quatro: as falhas eram silenciosas. Anexos descartados, mas reportados como enviados; consultas travando, mas exibidas como “nenhum resultado”; chaves lidas errado sem nenhum erro. É exatamente por isso que eram tão difíceis de encontrar — a primeira reação natural é duvidar de si mesmo, não do software. Todos os quatro estão corrigidos agora; se algum deles já te mordeu antes, vale a pena repetir essas operações depois de atualizar.

Nota: Estas correções chegaram ao branch main do Hermes Agent em 2026-08-09 e ainda não estão em uma tag de release (a última release continua sendo a v0.20.0). Para usá-las hoje, rode a partir do código-fonte — ou espere pela próxima release.