Pular para o conteúdo principal

Documentação oficial desta página · v0.20.6

Configuração do Telegram

O Hermes Agent se integra ao Telegram como um bot de conversa completo. Depois de conectado, você conversa com o seu agente de qualquer aparelho, manda áudios que são transcritos automaticamente, recebe resultados de tarefas agendadas e usa o agente em conversas de grupo. A integração é construída em cima do python-telegram-bot e suporta texto, voz, imagens e anexos de arquivo.

Passo 1: crie um bot pelo BotFather​

Todo bot do Telegram precisa de um token de API emitido pelo @BotFather, a ferramenta oficial de gerenciamento de bots do Telegram.

  1. Abra o Telegram e procure por @BotFather, ou acesse t.me/BotFather
  2. Envie /newbot
  3. Escolha um nome de exibição (por exemplo, "Hermes Agent") — pode ser qualquer coisa
  4. Escolha um nome de usuário — precisa ser único e terminar em bot (por exemplo, my_hermes_bot)
  5. O BotFather responde com o seu token de API. Ele se parece com isto:
123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
aviso

Mantenha o token do bot em segredo. Qualquer pessoa com esse token controla o seu bot. Se ele vazar, revogue na hora com /revoke no BotFather.

Passo 2: personalize o seu bot (opcional)​

Estes comandos do BotFather melhoram a experiência de uso. Mande mensagem para o @BotFather e use:

ComandoPara que serve
/setdescriptionO texto de "O que este bot faz?" mostrado antes de o usuário começar a conversar
/setabouttextTexto curto na página de perfil do bot
/setuserpicEnviar um avatar para o seu bot
/setcommandsDefinir o menu de comandos (o botão / na conversa)
/setprivacyControlar se o bot vê todas as mensagens do grupo (veja o Passo 3)
dica

Para o /setcommands, um conjunto inicial útil:

help - Show help information
new - Start a new conversation
sethome - Set this chat as the home channel

Indicador de status online/offline (opcional)​

Bots do Telegram não têm um pontinho real de presença online/offline — aquele ponto verde é um recurso de conta de usuário, não algo que a Bot API exponha para bots. A superfície mais próxima é a descrição curta do bot (a linha mostrada abaixo do nome no perfil do bot).

Habilite o status_indicator e o Hermes define essa descrição curta como Online quando o gateway conecta e Offline num desligamento limpo:

gateway:
platforms:
telegram:
extra:
status_indicator: true
# Textos personalizados opcionais (padrões: "Online" / "Offline"):
status_online: "🟢 Online"
status_offline: "🔴 Offline"

Observações:

  • A descrição curta é global do bot (visível para todo mundo), não por conversa. As pessoas veem isso na página de perfil do bot, não como um selo ao vivo dentro de uma conversa aberta.
  • Só um desligamento limpo do gateway (/stop, disconnect) escreve "Offline". Uma queda dura deixa o último status conhecido — a limitação inerente de um indicador feito com texto de perfil.
  • Vem desligado por padrão, porque muda o perfil global do bot.

Prioridade e teto do menu de comandos (opcional)​

O Hermes registra o menu de comandos automaticamente quando o gateway do Telegram sobe. O menu é montado a partir do registro central de comandos de barra mais os comandos elegíveis de plugin/skill, e depois é limitado para o Telegram aceitar o payload de forma confiável. O teto padrão é 60 comandos — o suficiente para manter visíveis todos os comandos embutidos mais os comandos de skill mais comuns.

Se você tem comandos locais ou de plugin que precisam continuar visíveis no seletor / do Telegram, priorize-os no ~/.hermes/config.yaml:

platforms:
telegram:
extra:
command_menu:
max_commands: 60
priority_mode: prepend # prepend | append | replace
priority:
- my_plugin_command

O priority_mode controla como a sua lista se combina com a lista de prioridade embutida do Hermes:

  • prepend: coloca os seus comandos primeiro, depois os padrões do Hermes
  • append: mantém os padrões do Hermes primeiro, depois os seus comandos
  • replace: usa só a sua lista na ordenação de prioridade

O Telegram permite até 100 BotCommands, mas payloads grandes de comando podem falhar. O Hermes usa 60 por padrão, por confiabilidade, e restringe os valores configurados a 1..100; use /commands para a lista completa de comandos.

Passo 3: modo de privacidade (crítico para grupos)​

Bots do Telegram têm um modo de privacidade que vem habilitado por padrão. Essa é, de longe, a maior fonte de confusão ao usar bots em grupos.

Com o modo de privacidade LIGADO, o seu bot só enxerga:

  • Mensagens que começam com um comando /
  • Respostas diretas às próprias mensagens do bot
  • Mensagens de serviço (entradas/saídas de membros, mensagens fixadas etc.)
  • Mensagens em canais onde o bot é administrador

Com o modo de privacidade DESLIGADO, o bot recebe todas as mensagens do grupo.

Como desligar o modo de privacidade​

  1. Mande mensagem para o @BotFather
  2. Envie /mybots
  3. Selecione o seu bot
  4. Vá em Bot Settings → Group Privacy → Turn off
aviso

Você precisa remover e adicionar o bot de novo em cada grupo depois de mudar a configuração de privacidade. O Telegram guarda em cache o estado de privacidade no momento em que o bot entra no grupo, e isso não é atualizado até o bot ser removido e adicionado outra vez.

dica

Uma alternativa a desligar o modo de privacidade: promover o bot a administrador do grupo. Bots administradores sempre recebem todas as mensagens, independentemente da configuração de privacidade, e isso evita mexer no modo de privacidade global.

Observar a conversa do grupo sem responder automaticamente​

Para um comportamento de grupo no estilo OpenClaw/Yuanbao, configure o Telegram para que o bot veja as mensagens comuns do grupo mas só responda quando for acionado diretamente:

telegram:
allowed_chats:
- "-1001234567890"
group_allowed_chats:
- "-1001234567890"
require_mention: true
observe_unmentioned_group_messages: true

Com esse modo habilitado, as mensagens de grupo sem menção vindas de conversas/tópicos explicitamente na lista de permissão são anexadas à transcrição da sessão compartilhada da conversa/tópico como contexto observado, mas não acionam o agente. O allowed_chats controla onde o bot responde; o group_allowed_chats autoriza a sessão de grupo compartilhada usada para o contexto observado, então use os mesmos IDs de conversa nesse modo. Uma menção @botname posterior, uma resposta ao bot ou um padrão de menção configurado, naquela mesma conversa/tópico da lista de permissão, pode usar aquele contexto observado. A mensagem que aciona o agente também é marcada com [nickname|user_id] e recebe um prompt de segurança por turno, para o modelo tratar as linhas observadas anteriores como contexto, não como instruções dirigidas ao bot.

Variáveis de ambiente equivalentes:

TELEGRAM_ALLOWED_CHATS=-1001234567890
TELEGRAM_GROUP_ALLOWED_CHATS=-1001234567890
TELEGRAM_OBSERVE_UNMENTIONED_GROUP_MESSAGES=true

Isso exige que o Telegram entregue as mensagens comuns de grupo ao gateway, então desligue o modo de privacidade no BotFather ou promova o bot a administrador do grupo, como descrito acima.

Passo 4: descubra o seu ID de usuário​

O Hermes Agent usa IDs numéricos de usuário do Telegram para controlar o acesso. O seu ID de usuário não é o seu nome de usuário — é um número como 123456789.

Método 1 (recomendado): mande mensagem para o @userinfobot — ele responde na hora com o seu ID de usuário.

Método 2: mande mensagem para o @get_id_bot — outra opção confiável.

Guarde esse número; você vai precisar dele no próximo passo.

Passo 5: configure o Hermes​

hermes gateway setup

Escolha Telegram quando for perguntado. O assistente pede o token do seu bot e os IDs de usuário permitidos, e escreve a configuração por você.

Opção B: configuração manual​

Adicione o seguinte ao ~/.hermes/.env:

TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
TELEGRAM_ALLOWED_USERS=123456789 # Separe por vírgula para vários usuários

Suba o gateway​

hermes gateway

O bot deve ficar online em alguns segundos. Mande uma mensagem para ele no Telegram para conferir.

Enviar arquivos gerados por terminais em Docker​

Se o seu backend de terminal é docker, lembre que os anexos do Telegram são enviados pelo processo do gateway, não de dentro do contêiner. Isso quer dizer que o caminho final de MEDIA:/... precisa ser legível na máquina hospedeira onde o gateway está rodando.

Cilada comum:

  • o agente escreve um arquivo dentro do Docker em /workspace/report.txt
  • o modelo emite MEDIA:/workspace/report.txt
  • a entrega no Telegram falha porque /workspace/report.txt só existe dentro do contêiner, não na máquina hospedeira

Padrão recomendado:

terminal:
backend: docker
docker_volumes:
- "/home/user/.hermes/cache/documents:/output"

Então:

  • escreva os arquivos dentro do Docker em /output/...
  • emita o caminho visível na máquina hospedeira no MEDIA:, por exemplo: MEDIA:/home/user/.hermes/cache/documents/report.txt

Se você já tem uma seção docker_volumes:, acrescente a nova montagem na mesma lista. Chaves duplicadas em YAML sobrescrevem as anteriores em silêncio.

Extensões de arquivo suportadas no MEDIA:​

O gateway extrai as marcações MEDIA:/caminho/do/arquivo das respostas do agente e entrega o arquivo referenciado como um anexo nativo da plataforma. Extensões suportadas em todas as plataformas de gateway:

CategoriaExtensões
Imagenspng, jpg, jpeg, gif, webp, bmp, tiff, svg
Áudiomp3, wav, ogg, m4a, opus, flac, aac
Vídeomp4, mov, webm, mkv, avi
Documentospdf, txt, md, csv, json, xml, html, yaml, yml, log
Escritóriodocx, xlsx, pptx, odt, ods, odp
Arquivos compactadoszip, rar, 7z, tar, gz, bz2
Livros / pacotesepub, apk, ipa

Tudo o que está nessa lista é entregue como anexo nativo nas plataformas que suportam isso (Telegram, Discord, Signal, Slack, WhatsApp, Feishu, Matrix etc.); nas plataformas sem suporte nativo, ele cai para um link ou um indicador em texto puro. As categorias em negrito foram adicionadas nas últimas versões — se você dependia de o modelo dizer here is the file: /path/to/report.docx, troque para MEDIA:/path/to/report.docx para a entrega nativa.

Modo webhook​

Por padrão, o Hermes se conecta ao Telegram por long polling — o gateway faz requisições de saída para os servidores do Telegram para buscar novidades. Isso funciona bem para implantações locais e sempre ligadas.

Para implantações em nuvem (Fly.io, Railway, Render etc.), o modo webhook sai mais barato. Essas plataformas conseguem acordar máquinas suspensas com tráfego HTTP de entrada, mas não com conexões de saída. Como o polling é de saída, um bot em polling nunca dorme. O modo webhook inverte a direção — o Telegram empurra as novidades para a URL HTTPS do seu bot, permitindo implantações que dormem quando estão ociosas.

Polling (padrão)Webhook
DireçãoGateway → Telegram (saída)Telegram → Gateway (entrada)
Melhor paraServidores locais, sempre ligadosPlataformas de nuvem com despertar automático
ConfiguraçãoSem configuração extraDefina o TELEGRAM_WEBHOOK_URL
Custo ociosoA máquina precisa ficar de péA máquina pode dormir entre as mensagens

Configuração​

Adicione o seguinte ao ~/.hermes/.env:

TELEGRAM_WEBHOOK_URL=https://my-app.fly.dev/telegram
TELEGRAM_WEBHOOK_SECRET="$(openssl rand -hex 32)" # obrigatório
# TELEGRAM_WEBHOOK_PORT=8443 # opcional, padrão 8443
VariávelObrigatóriaDescrição
TELEGRAM_WEBHOOK_URLSimURL HTTPS pública para onde o Telegram vai mandar as novidades. O caminho da URL é extraído automaticamente (por exemplo, /telegram no exemplo acima).
TELEGRAM_WEBHOOK_SECRETSim (quando o TELEGRAM_WEBHOOK_URL está definido)Token secreto que o Telegram devolve em toda requisição de webhook, para verificação. O gateway se recusa a subir sem ele — veja GHSA-3vpc-7q5r-276h. Gere com openssl rand -hex 32.
TELEGRAM_WEBHOOK_PORTNãoPorta local em que o servidor de webhook escuta (padrão: 8443).

Quando o TELEGRAM_WEBHOOK_URL está definido, o gateway sobe um servidor HTTP de webhook em vez de fazer polling. Quando não está definido, o modo de polling é usado — sem mudança de comportamento em relação às versões anteriores.

Exemplo de implantação em nuvem (Fly.io)​

  1. Adicione as variáveis de ambiente aos secrets do seu app no Fly.io:
fly secrets set TELEGRAM_WEBHOOK_URL=https://my-app.fly.dev/telegram
fly secrets set TELEGRAM_WEBHOOK_SECRET=$(openssl rand -hex 32)
  1. Exponha a porta do webhook no seu fly.toml:
[[services]]
internal_port = 8443
protocol = "tcp"

[[services.ports]]
handlers = ["tls", "http"]
port = 443
  1. Faça o deploy:
fly deploy

O log do gateway deve mostrar: [telegram] Connected to Telegram (webhook mode).

Suporte a proxy​

Se a API do Telegram está bloqueada ou você precisa rotear o tráfego por um proxy, defina uma URL de proxy específica do Telegram. Ela tem prioridade sobre as variáveis de ambiente genéricas HTTPS_PROXY / HTTP_PROXY.

Opção 1: config.yaml (recomendada)

telegram:
proxy_url: "socks5://127.0.0.1:1080"

Opção 2: variável de ambiente

TELEGRAM_PROXY=socks5://127.0.0.1:1080

Esquemas suportados: http://, https://, socks5://.

O proxy vale tanto para a conexão principal com o Telegram quanto para o transporte de IP de reserva. Se nenhum proxy específico do Telegram estiver definido, o gateway recorre a HTTPS_PROXY / HTTP_PROXY / ALL_PROXY (ou à detecção automática de proxy do sistema no macOS).

Se o caminho de descoberta de IPs de reserva não estiver saudável na sua máquina, defina HERMES_TELEGRAM_DISABLE_FALLBACK_IPS=true para manter a conexão fria no caminho simples do api.telegram.org. Você também pode limitar a descoberta de reserva por DNS-over-HTTPS com o HERMES_TELEGRAM_FALLBACK_DISCOVERY_TIMEOUT, em segundos; o padrão é 5.

Canal principal​

Use o comando /sethome em qualquer conversa do Telegram (privada ou em grupo) para designá-la como o canal principal. As tarefas agendadas (cron) entregam os resultados nesse canal.

Você também pode definir isso na mão no ~/.hermes/.env:

TELEGRAM_HOME_CHANNEL=-1001234567890
TELEGRAM_HOME_CHANNEL_NAME="My Notes"
dica

IDs de conversa de grupo são números negativos (por exemplo, -1001234567890). O ID da sua conversa privada é o mesmo que o seu ID de usuário.

Entregas de cron no modo de tópicos​

Se você tem o modo de tópicos habilitado na conversa privada com o bot, as mensagens de cron entregues na conversa raiz caem no saguão só de sistema — responder ali não abre sessão nenhuma e você vê o aviso de que "a conversa principal é reservada a comandos de sistema". Crie um tópico de fórum dedicado (por exemplo, Cron) e defina:

TELEGRAM_CRON_THREAD_ID=<topic_thread_id>

O TELEGRAM_CRON_THREAD_ID se sobrepõe ao TELEGRAM_HOME_CHANNEL_THREAD_ID apenas nas entregas de cron. As respostas naquele tópico continuam a sessão existente do tópico.

Mensagens de voz​

Voz de entrada (fala para texto)​

As mensagens de voz que você manda no Telegram são transcritas automaticamente pelo provedor de STT configurado no Hermes e injetadas como texto na conversa.

  • local usa o faster-whisper na máquina que roda o Hermes — sem necessidade de chave de API
  • groq usa o Groq Whisper e exige GROQ_API_KEY
  • openai usa o OpenAI Whisper e exige VOICE_TOOLS_OPENAI_KEY

Pular o STT: passar o arquivo de áudio bruto para o agente​

Se você prefere que o próprio agente cuide do áudio — para diarização, uma ferramenta de transcrição personalizada, ou só para arquivar a gravação — defina stt.enabled: false no ~/.hermes/config.yaml:

stt:
enabled: false

Com o STT desabilitado, o gateway ainda baixa o anexo de voz/áudio para o cache de áudio do Hermes, mas não o transcreve. O agente recebe a mensagem com um marcador assim:

[The user sent a voice message: /home/<user>/.hermes/cache/audio/<hash>.ogg]

As suas ferramentas ou skills podem então ler esse caminho direto (por exemplo, entregar para um pipeline local de diarização, para um modelo de transcrição mais rico, ou subir para um armazenamento de longo prazo). A extensão do arquivo reflete o formato original que o Telegram entregou (.ogg para notas de voz, .mp3/.m4a/etc. para anexos de áudio).

Isso combina naturalmente com a seção do servidor local da Bot API abaixo, que levanta o teto de 20MB do getFile do Telegram para 2GB — útil quando as gravações que você quer processar passam de alguns minutos.

Voz de saída (texto para fala)​

Quando o agente gera áudio por TTS, ele é entregue como bolhas de voz nativas do Telegram — aquelas redondas, que tocam ali mesmo.

  • OpenAI e ElevenLabs produzem Opus nativamente — sem configuração extra
  • Edge TTS (o provedor grátis padrão) gera MP3 e precisa do ffmpeg para converter para Opus:
# Ubuntu/Debian
sudo apt install ffmpeg

# macOS
brew install ffmpeg

Sem o ffmpeg, o áudio do Edge TTS é enviado como um arquivo de áudio comum (ainda dá para ouvir, mas usa o player retangular em vez da bolha de voz).

Configure o provedor de TTS no seu config.yaml, na chave tts.provider.

Arquivos grandes (>20MB) por um servidor local da Bot API​

A Bot API pública do Telegram limita os downloads do getFile a 20 MB, então qualquer nota de voz, arquivo de áudio, vídeo ou documento maior que isso é rejeitado em silêncio pelo Hermes com uma resposta de "grande demais". O jeito documentado de contornar isso é rodar um daemon local do telegram-bot-api — o mesmo software de servidor que o Telegram usa, mas rodando na sua rede. Um servidor local levanta o teto de arquivo para 2 GB, e o Hermes levanta sozinho o próprio teto interno quando vê uma base_url personalizada configurada.

Isso destrava fluxos como:

  • Mandar áudios longos para o bot (reuniões de 45 minutos, podcasts)
  • Subir vídeos grandes para processamento por ferramentas de visão
  • Arquivar áudio bruto para pipelines offline de diarização, alinhamento ou dados de treinamento

Passo 1: obtenha credenciais da API do Telegram​

O servidor local fala direto com a camada MTProto do Telegram (não com a Bot API pública), então ele precisa de credenciais MTProto:

  1. Acesse my.telegram.org/apps e entre com a sua conta do Telegram.
  2. Crie uma aplicação nova (qualquer nome e descrição curta servem).
  3. Copie o api_id e o api_hash — os dois são obrigatórios.

Passo 2: rode o servidor telegram-bot-api​

A imagem Docker aiogram/telegram-bot-api, mantida pela comunidade, é o caminho mais fácil. Um docker-compose.yaml mínimo (use o modo --local para habilitar os limites maiores):

services:
tg-bot-api:
image: aiogram/telegram-bot-api:latest
container_name: tg-bot-api
restart: unless-stopped
ports:
- "127.0.0.1:8081:8081" # amarre só no loopback; veja a nota de segurança
environment:
TELEGRAM_API_ID: "12345" # seu api_id do Passo 1
TELEGRAM_API_HASH: "abcdef..." # seu api_hash do Passo 1
TELEGRAM_LOCAL: "1" # habilita o modo --local (levanta de 20MB para 2GB)
volumes:
- ./tg-bot-api-data:/var/lib/telegram-bot-api

Suba:

docker compose up -d tg-bot-api
docker logs --tail 20 tg-bot-api
Segurança

O servidor local da Bot API recebe o token do seu bot no caminho da URL (por exemplo, /bot<TOKEN>/getMe) sem autenticação adicional. Qualquer pessoa que alcance a porta controla o seu bot por completo — lê todas as mensagens que ele vê, manda mensagens como ele etc. Amarre o contêiner em 127.0.0.1 e/ou coloque um proxy reverso na frente, numa rede privada. Nunca exponha a porta 8081 na internet pública.

Passo 3: desconecte o bot da API pública (uma única vez)​

Um bot só pode estar ativo em um servidor de Bot API por vez. Se o seu bot já estava rodando contra o api.telegram.org (o que é quase certo), você precisa desconectá-lo de lá explicitamente antes de o servidor local aceitá-lo:

curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/logOut"
# resposta esperada: {"ok":true,"result":true}

Este é um passo único de migração — você não repete a cada reinício. O Telegram entrega pelo novo servidor as mensagens recebidas depois do logOut.

Confira se o servidor local consegue falar com o Telegram em nome do bot:

curl "http://127.0.0.1:8081/bot<YOUR_BOT_TOKEN>/getMe"
# resposta esperada: {"ok":true,"result":{"id":...,"is_bot":true,...}}

Passo 4: aponte o Hermes para o servidor local​

Adicione as URLs em platforms.telegram.extra, no ~/.hermes/config.yaml:

platforms:
telegram:
extra:
base_url: "http://127.0.0.1:8081/bot"
base_file_url: "http://127.0.0.1:8081/file/bot"
local_mode: true # veja o Passo 5 abaixo — só defina isto se o diretório
# de dados do bot for legível pelo processo do Hermes
Use platforms.telegram.extra, não telegram.extra

No momento, só a forma platforms.<name>.extra é mesclada em profundidade na configuração da plataforma. Chaves colocadas direto num bloco telegram.extra de nível de cima são descartadas em silêncio.

Quando a base_url está definida, o Hermes:

  • Monta o cliente python-telegram-bot apontando para o servidor local
  • Levanta sozinho o teto interno de tamanho de documento/áudio de 20 MB para 2 GB
  • Informa o limite ativo na mensagem de erro de "grande demais" (Maximum: 2048 MB.), para ficar óbvio em qual modo você está

Reinicie o gateway e procure uma linha de log de confirmação:

hermes gateway restart
grep -E "Using custom Telegram base_url|Using Telegram local_mode" ~/.hermes/logs/gateway.log | tail

Passo 5: local_mode — acesso a arquivos no disco​

O servidor local tem duas maneiras de entregar arquivos:

  1. Sem --local (o padrão): os arquivos são servidos por HTTP em /file/bot<TOKEN>/<path>, igual à Bot API pública. O teto de 20MB continua valendo. Útil só como conserto de rede (por exemplo, quando o api.telegram.org está inacessível mas você consegue hospedar por conta própria); não é o que você quer para levantar o limite de tamanho.
  2. Com --local (definido pelo TELEGRAM_LOCAL=1 acima): os arquivos são escritos no sistema de arquivos do servidor e a resposta do getFile devolve um caminho absoluto em vez de uma URL HTTP. O teto de 20MB é levantado. O Hermes então precisa ler os bytes do disco, não por HTTP.

Para o caminho de leitura em disco funcionar, defina local_mode: true na configuração acima e garanta que o processo do Hermes consiga ler o caminho que o servidor devolve. Dois cenários:

  • Mesma máquina — telegram-bot-api e Hermes rodam no mesmo host. Monte o volume de dados num diretório que o Hermes consiga ler (por exemplo, /var/lib/telegram-bot-api) e garanta que a propriedade dos arquivos bata. O contêiner abandona privilégios para o usuário interno telegram-bot-api (o uid varia por imagem); a correção mais simples é adicionar user: "<UID>:<GID>" ao serviço do compose, para que os arquivos pertençam a um uid com o qual o Hermes já roda.
  • Máquinas diferentes — o servidor do bot roda num host (por exemplo, um NAS, uma VM separada) e o Hermes em outro. O diretório de dados do servidor precisa estar compartilhado com a máquina do Hermes no mesmo caminho absoluto que o servidor informa (normalmente /var/lib/telegram-bot-api). NFS funciona bem nisso; CIFS/SMB com remapeamento de montagem uid= é mais amigável se você não quiser lidar com incompatibilidades de uid no nível do sistema de arquivos.

Se local_mode: true está definido mas o Hermes não consegue dar stat no caminho de arquivo devolvido (permissões ou montagem errada), o python-telegram-bot recorre em silêncio a um getFile por HTTP contra o servidor local — que, no modo --local, responde com 404 Not Found. O sintoma aparece no gateway.log como:

[Telegram] Failed to cache voice: Not Found
telegram.error.InvalidToken: Not Found

Se você ver isso, o levantamento do teto está funcionando mas o compartilhamento de arquivos não. Confira com ls -la /var/lib/telegram-bot-api/<TOKEN>/voice/ a partir da máquina do Hermes, com o usuário sob o qual o gateway roda, e confirme que dá para fazer cat num arquivo sem erro de permissão.

Passo 6: teste​

Mande para o bot uma nota de voz ou um arquivo de áudio maior que 20 MB. Acompanhe o log do gateway:

tail -f ~/.hermes/logs/gateway.log | grep -iE "telegram|cache"

Você deve ver uma linha [Telegram] Cached user voice at /home/<user>/.hermes/cache/audio/... e nenhuma rejeição de "grande demais". Combinado com stt.enabled: false (acima), o caminho do arquivo de áudio original então chega na mensagem de entrada do agente, para processamento posterior.

Uso em conversas de grupo​

O Hermes Agent funciona em conversas de grupo do Telegram, com algumas ressalvas:

  • O modo de privacidade determina quais mensagens o bot consegue ver (veja o Passo 3)
  • O TELEGRAM_ALLOWED_USERS continua valendo — só usuários autorizados acionam o bot, mesmo em grupos
  • Você pode impedir o bot de responder à conversa comum do grupo com telegram.require_mention: true
  • Com telegram.require_mention: true, as mensagens de grupo são aceitas quando são:
    • respostas a alguma mensagem do bot
    • menções @botusername
    • /command@botusername (a forma de comando do menu de bots do Telegram, que inclui o nome do bot)
    • correspondências a alguma das suas palavras de ativação em regex configuradas em telegram.mention_patterns
  • Em grupos com vários bots Hermes, o telegram.exclusive_bot_mentions mantém o roteamento determinístico. Quando uma mensagem menciona explicitamente um ou mais nomes de usuário de bot do Telegram, só os perfis de bot mencionados a processam; os outros bots Hermes a ignoram antes de rodarem as reservas de resposta e de palavra de ativação. Isso vem habilitado por padrão.
  • Renomear o @username do bot no BotFather é percebido automaticamente — o Hermes segue o novo apelido no roteamento de menções sem reiniciar o gateway. Nomes de usuário colecionáveis (Fragment) que não terminam em bot também são suportados.
  • Use o telegram.ignored_threads para manter o Hermes calado em tópicos específicos de fórum do Telegram, mesmo quando o grupo permitiria respostas livres ou respostas acionadas por menção
  • Se o telegram.require_mention ficar indefinido ou falso, o Hermes mantém o comportamento anterior de grupo aberto e responde às mensagens comuns de grupo que consegue ver

Vários bots Hermes num mesmo grupo​

Se você roda vários perfis do Hermes no mesmo grupo do Telegram, crie um token de bot do Telegram por perfil e suba um gateway por perfil. Não reutilize o mesmo token de bot em vários gateways rodando; o Telegram rejeita polling simultâneo para o mesmo token.

Configuração de grupo recomendada:

telegram:
require_mention: true
exclusive_bot_mentions: true
mention_patterns: []

Com essa configuração, uma mensagem de grupo como @research_bot @ops_bot summarize this é processada só pelo research_bot e pelo ops_bot. Os outros bots Hermes do grupo ficam calados, mesmo que a mensagem seja resposta a alguma mensagem anterior deles ou que casasse com uma palavra de ativação compartilhada.

Defina exclusive_bot_mentions: false só para grupos antigos em que menções explícitas não devem se sobrepor aos gatilhos de resposta e de palavra de ativação.

Para operar vários perfis, rode o comando de gateway uma vez por perfil. Por exemplo:

# perfil padrão
hermes gateway start
hermes gateway status
hermes gateway stop

# perfis nomeados
hermes -p research gateway start
hermes -p research gateway status
hermes -p research gateway stop

Para uma frota pequena e fixa, use um laço de shell ou um script que chame hermes gateway <action> para o perfil padrão e hermes -p <profile> gateway <action> para cada perfil nomeado. Isso é mais confiável do que supor que um único comando no nível do processo controla todos os perfis nomeados em todo gerenciador de serviços.

Resolver problemas: funciona na conversa privada, mas não em grupos​

Se o bot responde numa conversa privada mas fica calado no grupo, confira estas barreiras, nesta ordem:

  1. Entrega do Telegram: desligue o modo de privacidade no BotFather, promova o bot a administrador, ou mencione o bot diretamente. O Hermes não consegue responder a mensagens de grupo que o Telegram nunca entrega ao bot.
  2. Reentre depois de mudar a privacidade: remova o bot do grupo e adicione de novo depois de mudar as configurações de privacidade no BotFather. O Telegram pode manter o antigo comportamento de entrega para as participações que já existem.
  3. Autorização no Hermes: garanta que quem enviou está listado em TELEGRAM_ALLOWED_USERS ou TELEGRAM_GROUP_ALLOWED_USERS, ou libere a conversa de grupo com o TELEGRAM_GROUP_ALLOWED_CHATS.
  4. Filtros de menção: se telegram.require_mention: true está definido, a conversa comum do grupo é ignorada, a menos que a mensagem seja um comando de barra, uma resposta ao bot, uma menção @botusername, ou uma correspondência aos mention_patterns configurados.
  5. Roteamento com vários bots: se um grupo tem vários bots, garanta que cada perfil do Hermes use um token de bot único e mantenha o exclusive_bot_mentions habilitado, a menos que você queira de propósito o comportamento antigo de gatilho compartilhado.

IDs de conversa negativos são normais em grupos e supergrupos do Telegram. Se você usa autorização por conversa, coloque esses IDs no TELEGRAM_GROUP_ALLOWED_CHATS, não na lista de permissão de usuários remetentes.

Exemplo de configuração de gatilho em grupo​

Adicione isto ao ~/.hermes/config.yaml:

telegram:
require_mention: true
exclusive_bot_mentions: true
mention_patterns:
- "^\\s*chompy\\b"
ignored_threads:
- 31
- "42"

Este exemplo permite todos os gatilhos diretos de sempre, mais as mensagens que começam com chompy, mesmo sem usar uma @menção. As mensagens nos tópicos 31 e 42 do Telegram são sempre ignoradas, antes de as checagens de menção e de resposta livre rodarem.

Observações sobre o mention_patterns​

  • Os padrões usam expressões regulares do Python
  • A correspondência ignora maiúsculas e minúsculas
  • Os padrões são checados tanto em mensagens de texto quanto em legendas de mídia
  • Padrões de regex inválidos são ignorados com um aviso nos logs do gateway, em vez de derrubar o bot
  • Se você quer que um padrão case só no começo da mensagem, ancore com ^

Tópicos em conversa privada (Bot API 9.4)​

A Bot API 9.4 do Telegram (fevereiro de 2026) trouxe os Tópicos em conversa privada — bots podem criar threads de tópico no estilo fórum direto em conversas privadas, sem precisar de supergrupo. Isso permite manter vários espaços de trabalho isolados dentro da sua conversa privada com o Hermes.

Caso de uso​

Se você trabalha em vários projetos de longo prazo, os tópicos mantêm o contexto separado:

  • Tópico "Website" — trabalho no seu serviço web de produção
  • Tópico "Research" — revisão de literatura e exploração de artigos
  • Tópico "General" — tarefas variadas e perguntas rápidas

Cada tópico ganha a própria sessão de conversa, histórico e contexto — completamente isolados dos outros.

Configuração​

Pré-requisitos

Antes de adicionar tópicos à sua configuração, o usuário precisa habilitar o modo Tópicos na conversa privada com o bot:

  1. Abra a sua conversa privada com o bot do Hermes no Telegram
  2. Toque no nome do bot no topo para abrir as informações da conversa
  3. Habilite Tópicos (o botão que transforma a conversa num fórum)

Sem isso, o Hermes vai registrar The chat is not a forum na subida e pular a criação de tópicos. Essa é uma configuração do lado do cliente do Telegram — o bot não consegue habilitar isso por conta própria.

Adicione os tópicos em platforms.telegram.extra.dm_topics, no ~/.hermes/config.yaml:

platforms:
telegram:
extra:
dm_topics:
- chat_id: 123456789 # Seu ID de usuário do Telegram
topics:
- name: General
icon_color: 7322096
- name: Website
icon_color: 9367192
- name: Research
icon_color: 16766590
skill: arxiv # Carrega uma skill automaticamente neste tópico

Campos:

CampoObrigatórioDescrição
nameSimNome de exibição do tópico
icon_colorNãoCódigo de cor do ícone no Telegram (inteiro)
icon_custom_emoji_idNãoID de emoji personalizado para o ícone do tópico
skillNãoSkill para carregar automaticamente em sessões novas neste tópico
thread_idNãoPreenchido automaticamente depois da criação do tópico — não defina na mão

Como funciona​

  1. Na subida do gateway, o Hermes chama createForumTopic para cada tópico que ainda não tem um thread_id
  2. O thread_id é gravado de volta no config.yaml automaticamente — os reinícios seguintes pulam a chamada de API
  3. Cada tópico mapeia para uma chave de sessão isolada: agent:main:telegram:dm:{chat_id}:{thread_id}
  4. As mensagens de cada tópico têm o próprio histórico de conversa, descarga de memória e janela de contexto

Tratamento da conversa raiz​

Por padrão, as mensagens enviadas na conversa privada raiz (fora de qualquer tópico) são processadas normalmente. Defina ignore_root_dm: true para transformar a conversa raiz num saguão — as mensagens comuns são ignoradas em silêncio para os usuários que têm tópicos de conversa privada configurados, enquanto os comandos de sistema (/start, /help, /status etc.) continuam funcionando.

platforms:
telegram:
extra:
ignore_root_dm: true
dm_topics:
- chat_id: 123456789
topics:
- name: General

A checagem é por conversa: só os usuários com pelo menos uma entrada em dm_topics terão a conversa raiz afetada. Usuários sem tópicos configurados não são afetados.

Vínculo de skill​

Tópicos com um campo skill carregam aquela skill automaticamente quando uma sessão nova começa no tópico. Isso funciona exatamente como digitar /skill-name no começo de uma conversa — o conteúdo da skill é injetado na primeira mensagem, e as mensagens seguintes o veem no histórico da conversa.

Por exemplo, um tópico com skill: arxiv vai ter a skill arxiv pré-carregada sempre que a sessão dele for reiniciada (por tempo ocioso, reinício diário ou /reset manual).

dica

Tópicos criados fora da configuração (por exemplo, chamando a API do Telegram na mão) são descobertos automaticamente quando chega uma mensagem de serviço forum_topic_created. Você também pode adicionar tópicos à configuração com o gateway rodando — eles são percebidos na próxima falha de cache.

Modo de conversa privada com várias sessões (/topic)​

Uma conversa privada com várias sessões, no estilo ChatGPT — um bot, muitas conversas em paralelo. Diferente do extra.dm_topics curado pelo operador, visto acima, este modo é dirigido pelo usuário: sem configuração, sem nomes de tópico declarados antes. O usuário final liga com /topic, depois toca no botão + do Telegram para criar quantos tópicos quiser, cada um sendo uma sessão do Hermes totalmente independente.

Subcomandos do /topic​

FormaContextoEfeito
/topicConversa raiz, ainda não habilitadoConfere as capacidades no BotFather, habilita o modo de várias sessões, cria o tópico System fixado
/topicConversa raiz, já habilitadoMostra o estado: sessões não vinculadas disponíveis para restaurar
/topicDentro de um tópicoMostra o vínculo de sessão do tópico atual
/topic helpQualquerUso, ali mesmo
/topic offConversa raizDesabilita o modo de várias sessões e limpa todos os vínculos de tópico desta conversa
/topic <session-id>Dentro de um tópicoRestaura uma sessão anterior do Telegram no tópico atual

Só usuários autorizados (lista de permissão via TELEGRAM_ALLOWED_USERS / configuração de autenticação da plataforma) podem rodar /topic. Um remetente não autorizado recebe uma recusa em vez da ativação.

Tópicos de conversa privada x modo de conversa privada com várias sessões​

extra.dm_topics (dirigido por configuração)/topic (dirigido pelo usuário)
Quem ativaO operador, no config.yamlO usuário final, mandando /topic
Lista de tópicosConjunto fixo declarado na configuraçãoO usuário cria/apaga tópicos à vontade
Nomes de tópicoEscolhidos pelo operadorEscolhidos pelo usuário; renomeados automaticamente para bater com o título da sessão do Hermes
Comportamento da conversa raizConversa normal (saguão, se ignore_root_dm: true)Vira um saguão de sistema (mensagens que não são comandos são rejeitadas)
Caso de uso principalEspaços de trabalho permanentes, com vínculo opcional de skillSessões paralelas improvisadas
Persistênciaextra.dm_topics na configuraçãoTabelas SQLite telegram_dm_topic_mode + telegram_dm_topic_bindings

Os dois recursos podem coexistir no mesmo bot — você rodaria /topic na conversa privada de um usuário, e o extra.dm_topics continua administrando os tópicos declarados pelo operador nas outras conversas.

Pré-requisitos​

No @BotFather, abra o seu bot → Bot Settings → Threads Settings:

  1. Ligue o Threaded Mode (habilita o has_topics_enabled)
  2. Não desabilite a criação de tópicos por usuários (mantém o allows_users_to_create_topics ligado)

Quando o usuário roda /topic pela primeira vez, o Hermes chama getMe para verificar as duas flags. Se alguma estiver desligada, o Hermes manda uma captura de tela da página de Threads Settings do BotFather e explica o que mudar — nenhuma ativação acontece até os pré-requisitos estarem cumpridos.

Fluxo de ativação​

Na conversa raiz, envie:

/topic

O Hermes vai:

  1. Conferir getMe().has_topics_enabled e allows_users_to_create_topics
  2. Se os dois forem verdadeiros, habilitar o modo de tópicos com várias sessões nesta conversa privada
  3. Criar e fixar um tópico System para estado/comandos (na medida do possível)
  4. Responder com uma lista das sessões anteriores do Telegram não vinculadas que o usuário pode restaurar

Depois da ativação, a conversa raiz é um saguão: prompts comuns são rejeitados com uma orientação apontando para All Messages. Comandos de sistema (/status, /sessions, /usage, /help etc.) continuam funcionando na raiz.

Criar um tópico novo (fluxo do usuário final)​

  1. Abra a conversa privada com o bot no Telegram
  2. Toque em All Messages no topo da interface do bot e mande qualquer mensagem
  3. O Telegram cria um tópico novo para aquela mensagem
  4. O Hermes responde dentro daquele tópico — o tópico agora é uma sessão independente

Todo tópico ganha o próprio histórico de conversa, estado de modelo, execução de ferramentas e ID de sessão. A chave de isolamento é agent:main:telegram:dm:{chat_id}:{thread_id} — idêntica ao isolamento dos tópicos de conversa privada dirigidos por configuração.

Tópicos renomeados automaticamente​

Quando o Hermes gera um título de sessão para um tópico (pelo pipeline de título automático, depois da primeira troca), o próprio tópico do Telegram é renomeado para bater — por exemplo, "New Topic" vira "Plano de migração do banco". A renomeação é na medida do possível: falhas são registradas mas não quebram a sessão.

Para desligar isso e manter intactos os nomes de tópico que você escolheu na mão, defina:

gateway:
platforms:
telegram:
extra:
disable_topic_auto_rename: true

Com essa flag ligada, o Hermes continua gerando um título interno de sessão (usado pelo hermes sessions, pela TUI etc.) mas nunca edita o nome do tópico no Telegram. É útil quando você organiza os tópicos na mão sob o Threaded Mode do BotFather e não quer que cada primeira resposta sobrescreva o título.

/new dentro de um tópico​

Reinicia a sessão do tópico atual (novo ID de sessão, histórico limpo) sem tocar nos outros tópicos. O Hermes responde com um lembrete de que, para trabalho em paralelo, criar outro tópico (pelo All Messages) costuma ser o que você quer.

Restaurar uma sessão anterior​

Dentro de um tópico, envie:

/topic <session-id>

Isso vincula o tópico atual a uma sessão existente do Hermes em vez de começar do zero. É útil para continuar uma conversa que começou antes de o modo de tópicos ser habilitado. Restrições:

  • A sessão de destino precisa pertencer ao mesmo usuário do Telegram
  • A sessão de destino não pode já estar vinculada a outro tópico

O Hermes confirma com o título da sessão e reapresenta a última mensagem do assistente, como contexto.

Para descobrir os IDs de sessão, mande /topic (sem argumento) na conversa raiz — o Hermes lista as sessões do Telegram do usuário que não estão vinculadas.

/topic dentro de um tópico (sem argumento)​

Mostra o vínculo do tópico atual: título da sessão, ID da sessão, e dicas sobre /new versus criar outro tópico.

Por dentro​

  • A ativação é persistida em telegram_dm_topic_mode(chat_id, user_id, enabled, ...), no state.db
  • Cada vínculo de tópico é persistido em telegram_dm_topic_bindings(chat_id, thread_id, session_id, ...) com ON DELETE CASCADE no session_id — podar uma sessão limpa automaticamente o vínculo de tópico dela
  • A migração SQLite do modo de tópicos precisa ser ativada: ela roda na primeira chamada de /topic, nunca na subida do gateway. Até um usuário rodar /topic neste perfil, o state.db fica intocado
  • Cada mensagem privada de entrada busca o vínculo (chat_id, thread_id) dela. Se existir, a busca roteia a mensagem para a sessão vinculada pelo SessionStore.switch_session(), para que o mapeamento de chave de sessão para ID de sessão fique consistente no disco
  • O /new dentro de um tópico reescreve a linha de vínculo para apontar para o novo ID de sessão, então a mensagem seguinte fica na sessão nova
  • Tópicos declarados em extra.dm_topics nunca são renomeados automaticamente — o nome escolhido pelo operador é preservado mesmo com o modo de várias sessões habilitado
  • Defina extra.disable_topic_auto_rename: true para desligar a renomeação automática em todos os tópicos da conversa (inclusive os tópicos improvisados criados pelo Threaded Mode)
  • O tópico General (fixado no topo) numa conversa privada com fórum habilitado é tratado como o saguão raiz, não importa se o Telegram entrega as mensagens dele com message_thread_id=1 ou sem thread_id
  • Os lembretes do saguão raiz são limitados a uma mensagem a cada 30 segundos por conversa — um usuário que esquece que o modo de tópicos está ligado e digita dez prompts na raiz não recebe dez respostas
  • As capturas de tela de configuração do BotFather são limitadas a um envio a cada 5 minutos por conversa — tentativas repetidas de /topic com as Threads Settings ainda desabilitadas não sobem a mesma imagem de novo
  • Um /background <prompt> iniciado dentro de um tópico entrega o resultado de volta no mesmo tópico; sessões em segundo plano não disparam a renomeação automática do tópico dono
  • O próprio /topic passa pela checagem de autorização de usuário do bot — conversas privadas não autorizadas recebem uma recusa em vez da ativação

Desabilitar o modo de várias sessões​

Mande /topic off na conversa raiz. O Hermes desliga a linha, limpa os vínculos (thread_id → session_id) da conversa, e a conversa raiz volta a ser uma conversa normal do Hermes. Os tópicos existentes no Telegram não são apagados — eles só param de ser tratados como sessões independentes. Rode /topic mais tarde para ligar de novo.

Se você precisar limpar na mão (por exemplo, um reinício em lote em muitas conversas), remova as linhas direto:

sqlite3 ~/.hermes/state.db \
"UPDATE telegram_dm_topic_mode SET enabled = 0 WHERE chat_id = '<your_chat_id>'; \
DELETE FROM telegram_dm_topic_bindings WHERE chat_id = '<your_chat_id>';"

Voltar para uma versão anterior do Hermes​

Se você voltar para uma versão do Hermes anterior ao /topic, o recurso simplesmente para de funcionar — as tabelas telegram_dm_topic_mode e telegram_dm_topic_bindings continuam no state.db mas são ignoradas pelo código mais antigo. As conversas privadas voltam ao isolamento nativo por thread (cada message_thread_id continua ganhando a própria sessão pelo build_session_key), então os seus tópicos existentes do Telegram continuam funcionando como sessões paralelas. A conversa raiz deixa de ser um saguão — as mensagens ali vão para o agente como antes. Atualizar de novo reativa o modo de várias sessões exatamente onde ele estava.

Vínculo de skill em tópicos de fórum de grupo​

Supergrupos com o modo Tópicos habilitado (também chamados de "tópicos de fórum") já ganham isolamento de sessão por tópico — cada thread_id mapeia para a própria conversa. Mas você pode querer carregar uma skill automaticamente quando chegam mensagens num tópico específico do grupo, exatamente como funciona o vínculo de skill nos tópicos de conversa privada.

Caso de uso​

Um supergrupo de time com tópicos de fórum para frentes de trabalho diferentes:

  • Tópico Engineering → carrega automaticamente a skill software-development
  • Tópico Research → carrega automaticamente a skill arxiv
  • Tópico General → sem skill, assistente de uso geral

Configuração​

Adicione os vínculos de tópico em platforms.telegram.extra.group_topics, no ~/.hermes/config.yaml:

platforms:
telegram:
extra:
group_topics:
- chat_id: -1001234567890 # ID do supergrupo
topics:
- name: Engineering
thread_id: 5
skill: software-development
- name: Research
thread_id: 12
skill: arxiv
- name: General
thread_id: 1
# Sem skill — uso geral

Campos:

CampoObrigatórioDescrição
chat_idSimO ID numérico do supergrupo (número negativo começando com -100)
nameNãoRótulo legível para o tópico (apenas informativo)
thread_idSimID do tópico de fórum do Telegram — visível nos links t.me/c/<group_id>/<thread_id>
skillNãoSkill para carregar automaticamente em sessões novas neste tópico

Como funciona​

  1. Quando chega uma mensagem num tópico de grupo mapeado, o Hermes busca o chat_id e o thread_id na configuração de group_topics
  2. Se a entrada correspondente tem um campo skill, essa skill é carregada automaticamente na sessão — igual ao vínculo de skill em tópico de conversa privada
  3. Tópicos sem a chave skill ganham só o isolamento de sessão (comportamento existente, sem mudança)
  4. Valores de thread_id ou de chat_id não mapeados passam batido em silêncio — sem erro, sem skill

Diferenças em relação aos tópicos de conversa privada​

Tópicos de conversa privadaTópicos de grupo
Chave de configuraçãoextra.dm_topicsextra.group_topics
Criação do tópicoO Hermes cria os tópicos pela API se falta o thread_idO administrador cria os tópicos na interface do Telegram
thread_idPreenchido automaticamente depois da criaçãoPrecisa ser definido na mão
icon_color / icon_custom_emoji_idSuportadosNão se aplica (o administrador controla a aparência)
Vínculo de skill✓✓
Isolamento de sessão✓✓ (já embutido nos tópicos de fórum)
dica

Para achar o thread_id de um tópico, abra o tópico no Telegram Web ou Desktop e olhe a URL: https://t.me/c/1234567890/5 — o último número (5) é o thread_id. O chat_id de supergrupos é o ID do grupo com o prefixo -100 (por exemplo, o grupo 1234567890 vira -1001234567890).

Recursos recentes da Bot API​

  • Bot API 9.4 (fev. de 2026): Tópicos em conversa privada — bots podem criar tópicos de fórum em conversas privadas pelo createForumTopic. O Hermes usa isso para dois recursos distintos: os Tópicos em conversa privada curados pelo operador (dirigidos por configuração, lista fixa de tópicos) e o modo de conversa privada com várias sessões dirigido pelo usuário (ativado por /topic, tópicos criados pelo usuário sem limite).
  • Política de privacidade: o Telegram agora exige que os bots tenham uma política de privacidade. Defina uma pelo BotFather com /setprivacy_policy, ou o Telegram pode gerar um texto genérico automaticamente. Isso é especialmente importante se o seu bot é voltado ao público.
  • Bot API 9.5 (mar. de 2026): streaming nativo pelo sendMessageDraft. O Hermes suporta a API nativa de rascunho em streaming do Telegram como um transporte opcional para conversas privadas. O padrão continua sendo o caminho antigo do editMessageText, porque as prévias de rascunho podem visivelmente encolher e ser redesenhadas em alguns clientes do Telegram.

Transporte de streaming (gateway.streaming.transport)​

Quando o streaming está habilitado (gateway.streaming.enabled: true), o Hermes escolhe um de quatro transportes:

ValorComportamento
auto (padrão)Streaming nativo por rascunho nas conversas suportadas (hoje, conversas privadas do Telegram); caminho antigo baseado em edição no resto. Recua com elegância se um quadro de rascunho falhar.
draftForça os rascunhos nativos. Registra um rebaixamento e recua para a edição se a conversa não suportar rascunhos (por exemplo, grupos/tópicos).
editO antigo editMessageText progressivo, para todo tipo de conversa.
offDesliga o streaming por completo (só a resposta final, sem atualizações progressivas).

No ~/.hermes/config.yaml:

gateway:
streaming:
enabled: true
transport: auto # auto | draft | edit | off

O que você vê em conversas privadas com edit (padrão) — o gateway manda uma mensagem normal de prévia e a atualiza progressivamente pelo editMessageText, evitando o efeito de encolher/reverter da prévia de rascunho do Telegram.

O que você vê em conversas privadas com auto ou draft — o Telegram mostra uma prévia de rascunho animada, que atualiza token por token. Quando a resposta termina, ela é entregue como uma mensagem comum e a prévia de rascunho desaparece naturalmente no cliente. Rascunhos não têm id de mensagem, então a resposta final é o que fica no seu histórico de conversa.

E em grupos, supergrupos, tópicos de fórum? O Telegram restringe o sendMessageDraft a conversas privadas. O gateway recua de forma transparente para o caminho baseado em edição em todo o resto — a mesma experiência de antes.

E se um quadro de rascunho falhar? Qualquer falha (erro de rede passageiro, rejeição do lado do servidor, instalação antiga do python-telegram-bot) devolve aquela resposta ao caminho baseado em edição pelo resto do fluxo. A resposta seguinte ganha uma tentativa nova.

Mensagens ricas (Bot API 10.1). As respostas finais que contêm construções que o caminho antigo de MarkdownV2 degrada — tabelas, listas de tarefas, <details> recolhíveis e matemática em bloco — são enviadas com o sendRichMessage nativo do Telegram usando o markdown cru do agente, então elas renderizam nativamente, sem achatamento no cliente. Em conversas privadas, o padrão rich_drafts: false mantém a prévia de streaming simples — ela usa o transporte de rascunho efêmero do Telegram com a renderização antiga (tabelas e outras construções exclusivas do modo rico continuam como markdown cru na prévia) — e então persiste a resposta concluída com o sendRichMessage. Definir rich_drafts: true faz a prévia ao vivo usar o sendRichMessageDraft também. Fluxos baseados em edição podem finalizar uma prévia existente no lugar, pelo parâmetro rich_message do editMessageText. Respostas comuns (prosa simples, negrito/itálico, listas simples) continuam no caminho do MarkdownV2, por consistência de peso de fonte e espaçamento entre os clientes.

O caminho rico é pulado automaticamente quando o conteúdo passa do limite de 32.768 caracteres de texto rico, e qualquer rejeição do Telegram (endpoint não suportado num python-telegram-bot mais antigo, erro de parser, blocos/colunas grandes demais) recua de forma transparente para o caminho do MarkdownV2 — a sua mensagem nunca é perdida. Erros passageiros/de rede não são reenviados em silêncio (sem mensagem final duplicada).

Reserva de MarkdownV2. Quando o caminho rico não está disponível para uma mensagem, o Hermes converte o markdown para MarkdownV2. Como o MarkdownV2 não tem sintaxe nativa de tabela, as tabelas com barra vertical são normalizadas:

  • Tabelas pequenas são achatadas em marcadores por grupo de linha — cada linha vira uma lista com marcadores legível, sob os títulos das colunas. Bom para 2 a 4 colunas e células curtas.
  • Tabelas maiores ou mais largas recuam para um bloco de código cercado com colunas alinhadas, para nada desmoronar.

Mensagens ricas precisam ser ativadas. O padrão continua no caminho antigo do MarkdownV2, porque os clientes atuais do Telegram podem dificultar copiar mensagens ricas da Bot API como texto puro, o que dói especialmente em trechos de comando e em passagens para o celular. Para habilitar a renderização nativa de tabelas/listas de tarefas/details/matemática:

gateway:
platforms:
telegram:
extra:
rich_messages: true
rich_drafts: false

Essa configuração é sobre compatibilidade de renderização e de cópia no cliente; o Hermes já recua automaticamente quando o Telegram rejeita a chamada da API rica. O rich_drafts controla se a prévia de streaming na conversa privada renderiza rico (sendRichMessageDraft) e fica desligado por padrão porque o Telegram Desktop/macOS pode sobrepor visualmente os quadros de rascunho rico até a conversa se redesenhar; com ele desligado, a prévia flui simples e a resposta final ainda chega como Mensagem Rica nativa. Se você só quer o comportamento antigo de "sempre bloco de código" nas tabelas, mantendo as mensagens ricas habilitadas, desligue a normalização de tabela definindo telegram.pretty_tables: false no config.yaml (padrão: true).

Prévias de link. O Telegram gera prévias de link automaticamente para as URLs nas mensagens de bot. Se você prefere suprimir isso (uma saída longa de /tools, uma resposta do agente que menciona dez links etc.):

gateway:
platforms:
telegram:
extra:
disable_link_previews: true

Quando isso está habilitado, o Hermes anexa o LinkPreviewOptions(is_disabled=True) do Telegram em toda mensagem de saída e recorre ao parâmetro antigo disable_web_page_preview nas versões mais velhas do python-telegram-bot.

Lista de permissão de grupos​

Grupos e conversas de fórum do Telegram têm duas barreiras ortogonais que você pode configurar:

  • IDs de usuário remetente (group_allow_from / TELEGRAM_GROUP_ALLOWED_USERS) — lista de permissão por remetente que vale só para mensagens de grupo/fórum. Use quando você quiser que usuários específicos consigam acionar o bot em grupos sem adicioná-los ao TELEGRAM_ALLOWED_USERS (o que também daria acesso à conversa privada).
  • IDs de conversa (group_allowed_chats / TELEGRAM_GROUP_ALLOWED_CHATS) — lista de permissão por conversa. Qualquer membro desses grupos/fóruns pode interagir com o bot. Útil para bots de time/suporte, em que a própria participação no grupo é o sinal de acesso.
gateway:
platforms:
telegram:
extra:
# Acesso global (conversas privadas + grupos). Estes usuários sempre podem acionar o bot.
allow_from:
- "123456789"
# IDs de remetente permitidos só em grupos/fóruns. NÃO dá acesso à conversa privada.
group_allow_from:
- "987654321"
# Grupos/fóruns inteiros — qualquer membro está autorizado.
group_allowed_chats:
- "-1001234567890"

Variáveis de ambiente equivalentes:

TELEGRAM_ALLOWED_USERS="123456789"
TELEGRAM_GROUP_ALLOWED_USERS="987654321"
TELEGRAM_GROUP_ALLOWED_CHATS="-1001234567890"

Comportamento:

  • O TELEGRAM_ALLOWED_USERS cobre todos os tipos de conversa (privadas, grupos, fóruns).
  • O TELEGRAM_GROUP_ALLOWED_USERS só autoriza os remetentes listados em grupos/fóruns. Eles continuam sem poder mandar mensagem privada para o bot, a não ser que estejam no TELEGRAM_ALLOWED_USERS.
  • Uma conversa no TELEGRAM_GROUP_ALLOWED_CHATS autoriza todo membro daquela conversa, não importa quem envia.
  • Use * em qualquer um desses para permitir qualquer remetente/conversa.
  • Isso se soma aos gatilhos existentes de menção/padrão e ao group_topics + ignored_threads.

Migração de antes do PR #17686​

Antes dessa separação, o TELEGRAM_GROUP_ALLOWED_USERS era o único botão e as pessoas colocavam IDs de conversa nele. Por compatibilidade com o que já existia, valores com formato de ID de conversa (começando com -) no TELEGRAM_GROUP_ALLOWED_USERS continuam sendo respeitados como IDs de conversa, e um aviso de descontinuação é registrado uma vez. Migração:

# Antigo (ainda funciona, mas está descontinuado)
TELEGRAM_GROUP_ALLOWED_USERS="-1001234567890"

# Novo
TELEGRAM_GROUP_ALLOWED_CHATS="-1001234567890"

Liberação para visitantes por @menção (guest_mode)​

Numa configuração típica, o group_allowed_chats é uma barreira dura: mensagens de grupos fora da lista são descartadas em silêncio, mesmo se um membro @menciona o bot explicitamente. Esse é o padrão certo para bots de suporte / de time.

Para configurações mais informais — grupos de amigos em que você quer o bot quase sempre calado mas disponível de vez em quando, num chamado explícito — habilite o guest_mode:

gateway:
platforms:
telegram:
extra:
group_allowed_chats:
- "-1001234567890" # seu grupo principal na lista de permissão
guest_mode: true # grupos fora da lista: permite só com @menção

Equivalente em variável de ambiente:

TELEGRAM_GUEST_MODE=true

Padrão: false.

Com guest_mode: true, uma mensagem de um grupo fora da lista de permissão é processada só se ela @menciona o bot explicitamente. A menção é obrigatória em cada turno — não existe grude de sessão nas interações de visitante, então o bot nunca se envolve sozinho numa conversa de grupo de amigos em que não foi chamado.

Conversas privadas e grupos na lista de permissão se comportam exatamente como antes.

Controle de acesso aos comandos de barra​

Por padrão, todo usuário permitido pode rodar todo comando de barra. Para dividir a sua lista de permissão entre administradores (acesso total aos comandos de barra) e usuários comuns (só os comandos que você habilitar explicitamente), adicione allow_admin_from e user_allowed_commands ao bloco extra da plataforma:

gateway:
platforms:
telegram:
extra:
# Listas de permissão que já existiam (sem mudança)
allow_from:
- "123456789" # administrador
- "555555555" # usuário comum
- "777777777" # usuário comum

# NOVO — administradores ganham todos os comandos de barra (embutidos + de plugin)
allow_admin_from:
- "123456789"

# NOVO — usuários permitidos que não são administradores só rodam estes comandos de barra.
# /help e /whoami são sempre permitidos, para o usuário ver o próprio acesso.
user_allowed_commands:
- status
- model
- history

# Opcional: listas separadas de administrador/comandos para grupos
group_allow_admin_from:
- "123456789"
group_user_allowed_commands:
- status

Comportamento:

  • Um usuário listado em allow_admin_from para um escopo (conversa privada ou grupo) pode rodar todo comando de barra registrado — comandos embutidos E os registrados por plugin — pelo registro ao vivo.
  • Um usuário no allow_from mas não no allow_admin_from só pode rodar os comandos listados em user_allowed_commands, mais o piso sempre permitido: /help e /whoami.
  • A conversa comum (mensagens que não são de barra) não é afetada. Usuários que não são administradores continuam falando com o agente normalmente, só não conseguem acionar comandos arbitrários.
  • Compatibilidade com o que já existe: se o allow_admin_from não estiver definido para um escopo, o controle de comandos de barra fica desabilitado naquele escopo. Instalações existentes continuam funcionando sem mudança nenhuma.
  • Ser administrador na conversa privada não implica ser administrador em grupo. Cada escopo tem a própria lista de administradores.
  • Se só o group_allow_admin_from estiver definido, o escopo de conversa privada continua no modo sem restrição (compatível com o que já existia).

Use o /whoami para ver o escopo ativo, o seu nível (administrador / usuário / sem restrição) e quais comandos de barra você pode rodar.

Seletor interativo de modelo​

Quando você manda /model sem argumentos numa conversa do Telegram, o Hermes mostra um teclado interativo embutido para trocar de modelo:

  1. Seleção de provedor — botões mostrando cada provedor disponível com a contagem de modelos (por exemplo, "OpenAI (15)", "✓ Anthropic (12)" para o provedor atual).
  2. Seleção de modelo — lista de modelos paginada, com navegação Prev/Next, um botão Back para voltar aos provedores, e Cancel.

O modelo e o provedor atuais aparecem no topo. Toda a navegação acontece editando a mesma mensagem no lugar (sem entulhar a conversa).

dica

Se você sabe o nome exato do modelo, digite /model <name> direto para pular o seletor. Você também pode digitar /model <name> --global para persistir a mudança entre sessões.

IPs de reserva por DNS-over-HTTPS​

Em algumas redes restritas, o api.telegram.org pode resolver para um IP inacessível. O adaptador do Telegram inclui um mecanismo de IP de reserva que repete as conexões de forma transparente contra IPs alternativos, preservando o nome de host TLS e o SNI corretos.

Como funciona​

  1. Se o TELEGRAM_FALLBACK_IPS está definido, esses IPs são usados direto.
  2. Se não, o adaptador consulta automaticamente o DNS do Google e o DNS da Cloudflare por DNS-over-HTTPS (DoH) para descobrir IPs alternativos do api.telegram.org.
  3. IPs IPv4 conhecidos da API do Telegram são tentados antes do nome de host api.telegram.org, que é dual-stack. Um caminho IPv6 que engole pacotes pode ficar parado no connect() sem dar erro, o que antes prendia o laço de eventos e o prazo de 30s de inicialização nunca disparava.
  4. Se o DoH também estiver bloqueado ou estourar o tempo, uma lista semente IPv4 fixa no código (149.154.166.110, 149.154.167.220) é usada como aquela lista IPv4-primeiro. O nome de host continua sendo o último recurso.
  5. Quando um caminho dá certo, ele fica "grudado" — as requisições seguintes o usam direto. O nome de host é mantido como último recurso, para redes só de IPv6.

Configuração​

# IPs de reserva explícitos (separados por vírgula)
TELEGRAM_FALLBACK_IPS=149.154.167.220,149.154.167.221

Ou no ~/.hermes/config.yaml:

platforms:
telegram:
extra:
fallback_ips:
- "149.154.167.220"
dica

Normalmente você não precisa configurar isso na mão. A descoberta automática por DoH resolve a maioria dos cenários de rede restrita. A variável de ambiente TELEGRAM_FALLBACK_IPS só é necessária se o DoH também estiver bloqueado na sua rede. Se o IPv6 estiver quebrado na máquina, você também pode definir network.force_ipv4: true no config.yaml para pular as consultas AAAA em todo o processo.

Suporte a proxy​

Se a sua rede exige um proxy HTTP para alcançar a internet (comum em ambientes corporativos), o adaptador do Telegram lê automaticamente as variáveis de ambiente padrão de proxy e roteia todas as conexões por ele.

Variáveis suportadas​

O adaptador confere estas variáveis de ambiente em ordem, usando a primeira que estiver definida:

  1. HTTPS_PROXY
  2. HTTP_PROXY
  3. ALL_PROXY
  4. https_proxy / http_proxy / all_proxy (variantes em minúsculas)

Configuração​

Defina o proxy no seu ambiente antes de subir o gateway:

export HTTPS_PROXY=http://proxy.example.com:8080
hermes gateway

Ou adicione ao ~/.hermes/.env:

HTTPS_PROXY=http://proxy.example.com:8080

O proxy vale tanto para o transporte principal quanto para todos os transportes de IP de reserva. Nenhuma configuração adicional do Hermes é necessária — se a variável de ambiente está definida, ela é usada automaticamente.

observação

Isso cobre a camada de transporte de reserva personalizada que o Hermes usa nas conexões com o Telegram. O cliente httpx padrão, usado no resto, já respeita as variáveis de ambiente de proxy nativamente.

Reações a mensagens​

O bot pode adicionar reações de emoji às mensagens, como retorno visual do processamento:

  • 👀 quando o bot começa a processar a sua mensagem
  • ✅ quando a resposta é entregue com sucesso
  • ❌ se acontece um erro durante o processamento

As reações vêm desabilitadas por padrão. Habilite no config.yaml:

telegram:
reactions: true

Ou por variável de ambiente:

TELEGRAM_REACTIONS=true
observação

Diferente do Discord (em que as reações se acumulam), a Bot API do Telegram substitui todas as reações do bot numa única chamada. A transição de 👀 para ✅/❌ acontece de forma atômica — você não vai ver as duas ao mesmo tempo.

dica

Se o bot não tem permissão para adicionar reações num grupo, as chamadas de reação falham em silêncio e o processamento da mensagem continua normalmente.

Prompts por canal​

Atribua prompts de sistema efêmeros a grupos ou tópicos de fórum específicos do Telegram. O prompt é injetado em tempo de execução, em todo turno — nunca persistido no histórico da transcrição — então as mudanças valem na hora.

telegram:
channel_prompts:
"-1001234567890": |
You are a research assistant. Focus on academic sources,
citations, and concise synthesis.
"42": |
This topic is for creative writing feedback. Be warm and
constructive.

As chaves são IDs de conversa (grupos/supergrupos) ou IDs de tópico de fórum. Em grupos com fórum, os prompts no nível do tópico se sobrepõem ao prompt do grupo:

  • Mensagem no tópico 42, dentro do grupo -1001234567890 → usa o prompt do tópico 42
  • Mensagem no tópico 99 (sem entrada explícita) → recorre ao prompt do grupo -1001234567890
  • Mensagem num grupo sem entrada → nenhum prompt de canal é aplicado

Chaves numéricas de YAML são normalizadas para texto automaticamente.

Resolver problemas​

ProblemaSolução
O bot não responde nadaConfira se o TELEGRAM_BOT_TOKEN está correto. Veja os logs do hermes gateway procurando erros.
O bot responde "unauthorized"O seu ID de usuário não está no TELEGRAM_ALLOWED_USERS. Confira de novo com o @userinfobot.
O bot ignora as mensagens de grupoProvavelmente o modo de privacidade está ligado. Desligue (Passo 3) ou faça do bot um administrador do grupo. Lembre de remover e adicionar o bot de novo depois de mudar a privacidade.
Mensagens de voz não transcritasConfira se o STT está disponível: instale o faster-whisper para transcrição local, ou defina GROQ_API_KEY / VOICE_TOOLS_OPENAI_KEY no ~/.hermes/.env.
As respostas de voz vêm como arquivo, não como bolhaInstale o ffmpeg (necessário para a conversão de Opus do Edge TTS).
Token do bot revogado/inválidoGere um token novo com /revoke e depois /newbot, ou com /token no BotFather. Atualize o seu arquivo .env.
O webhook não recebe novidadesConfira se o TELEGRAM_WEBHOOK_URL é acessível publicamente (teste com curl). Garanta que a sua plataforma/proxy reverso encaminhe o tráfego HTTPS de entrada da porta da URL para a porta local de escuta configurada no TELEGRAM_WEBHOOK_PORT (elas não precisam ser o mesmo número). Garanta que o SSL/TLS está ativo — o Telegram só envia para URLs HTTPS. Confira as regras de firewall.

Aprovação de execução​

Quando o agente tenta rodar um comando potencialmente perigoso, ele pede a sua aprovação na conversa:

⚠️ This command is potentially dangerous (recursive delete). Reply "yes" to approve.

Responda "yes"/"y" para aprovar ou "no"/"n" para negar.

Perguntas interativas (clarify)​

Quando o agente chama a ferramenta clarify — para perguntar qual abordagem você prefere, colher retorno depois de uma tarefa, ou confirmar antes de uma decisão importante — o Telegram desenha a pergunta com botões de teclado embutido:

❓ Which framework should I use for the dashboard?

[1. Next.js] [2. Remix] [3. Astro] [✏️ Other (type answer)]

Toque num botão para responder, ou toque em Other para digitar uma resposta livre (a próxima mensagem que você mandar vira a resposta). Chamadas de clarify abertas (sem opções pré-definidas) pulam os botões e simplesmente capturam a sua próxima mensagem.

Configure o tempo limite de resposta pelo agent.clarify_timeout, no ~/.hermes/config.yaml (padrão de 600 segundos). Se você não responder dentro do tempo, o agente se desbloqueia com uma mensagem sentinela e se adapta em vez de ficar travado.

Volume de notificações push​

O Telegram dispara uma notificação push em cada mensagem que o bot manda. Em turnos longos do agente, que emitem bolhas de progresso de ferramenta, atualizações de streaming e retornos de estado, isso fica barulhento rápido. O adaptador do Telegram tem dois modos de notificação:

ModoComportamento
important (padrão)Só as respostas finais, os pedidos de aprovação e as confirmações de comando de barra tocam. Progresso de ferramenta, pedaços de streaming e mensagens de estado são entregues com disable_notification=true.
allToda mensagem de saída dispara uma notificação push. Comportamento antigo; ative se você realmente quer ouvir sobre cada chamada de ferramenta.

Configure no ~/.hermes/config.yaml:

display:
platforms:
telegram:
notifications: important # ou "all"

Sobreposição por variável de ambiente (prática para um teste A/B rápido):

HERMES_TELEGRAM_NOTIFICATIONS=all

Valores desconhecidos registram um aviso e recuam para important.

Mensagens de estado editadas no lugar​

O adaptador do Telegram roteia os retornos recorrentes de estado do agente (por exemplo, "Compressing context…", "Calling tool…") pelo send_or_update_status(), que mantém um cache {(chat_id, status_key) → message_id} e edita a bolha existente nas emissões seguintes, em vez de acrescentar uma nova a cada vez. Valores distintos de status_key ganham as próprias mensagens; conversas distintas nunca colidem. Se a edição falha (por exemplo, o usuário apagou a mensagem, ou ela é mais velha do que o Telegram permite editar), a entrada do cache é descartada e a próxima emissão posta uma mensagem nova e guarda o ID dela. Sem configuração nenhuma — esse é o comportamento padrão do Telegram. Outros adaptadores que não implementam o send_or_update_status caem no send() simples, sem mudança.

Fixar a mensagem de entrada do usuário durante o turno do agente​

Quando um usuário manda uma mensagem que aciona um turno do agente, o adaptador do Telegram fixa aquela mensagem de entrada pela duração do turno e a desafixa quando a resposta termina — um indicador visual leve de que o bot está trabalhando ativamente naquela mensagem, e não a ignorando. A fixação usa disable_notification=true para evitar avisos extras. Sem configuração nenhuma.

Segurança​

aviso

Sempre defina o TELEGRAM_ALLOWED_USERS para restringir quem pode interagir com o seu bot. Sem isso, o gateway nega todos os usuários por padrão, como medida de segurança.

Nunca compartilhe o token do seu bot publicamente. Se ele for comprometido, revogue na hora com o comando /revoke do BotFather.

Para mais detalhes, veja a documentação de segurança. Você também pode usar o pareamento por conversa privada para uma abordagem mais dinâmica de autorização de usuários.