DMs do Telegram empilhando numa thread só? Dê um tópico novo para cada mensagem

Você toca três coisas ao mesmo tempo no Telegram: caçando um bug em produção, escrevendo o relatório semanal e ajustando um script para um amigo. Então liga o modo /topic e dá uma thread para cada uma. Cenário perfeito — até o dedo escorregar e você digitar uma linha direto na janela principal do chat em vez de num tópico.
Essa mensagem não abre uma thread nova. Ela cai no tópico que você usou por último. Agora seu relatório semanal tem uma conclusão de debugging dentro dele, e o modelo começa animado a misturar as duas coisas. Você rola a conversa para cima por um bom tempo até achar o momento em que deu errado.
O modo de tópicos não está quebrado; ele faz uma escolha conservadora — mensagem no chat raiz significa “continue a última conversa”. Se você prefere que toda mensagem raiz comece do zero, o Hermes mesclou um interruptor exatamente para isso em 19 de outubro: dm_topic_auto_transfer.
Como o modo de tópicos se comporta hoje
Envie /topic numa DM e o Hermes verifica se o bot pode criar tópicos (o Threaded Mode precisa estar ligado no BotFather), habilita o modo de tópicos multi-sessão para aquele chat, cria um tópico System fixado para status e comandos, e oferece restaurar sessões anteriores que nunca foram ligadas a um tópico.
A partir daí o chat raiz vira um lobby: prompts normais são rejeitados com uma orientação apontando para All Messages, enquanto comandos de sistema como /status, /sessions, /usage e /help continuam funcionando ali.
Cada tópico é uma sessão independente — histórico próprio, estado de modelo próprio, execução de ferramentas própria e session id próprio. A chave de isolamento é agent:main:telegram:dm:{chat_id}:{thread_id}, então dois tópicos na mesma DM são duas conversas diferentes do ponto de vista do Hermes.
O detalhe chato é a escolha conservadora acima: alguns clientes entregam uma mensagem digitada no chat raiz sem message_thread_id. O Hermes trata isso como continuação e responde no seu tópico mais recentemente ativo — o que a documentação chama de lobby recovery. O lembrete que ele envia para te empurrar de volta a um tópico tem limite de uma mensagem a cada 30 segundos por (profile, chat), então esquecer e digitar dez prompts seguidos não gera dez respostas.
O interruptor: uma chave de configuração
Adicione uma linha no config.yaml do seu profile:
gateway:
platforms:
telegram:
extra:
dm_topic_auto_transfer: true # default: false
A chave de nível superior telegram.extra.dm_topic_auto_transfer também funciona (é a que aparece em Desktop Settings). É estritamente opt-in: deixe de fora e nada muda, incluindo o fallback para o seu tópico mais recente.
Com ela ligada, uma mensagem simples na DM raiz faz o seguinte:
- O Hermes cria um tópico novo na hora (com o nome “Hermes Chat” até o pipeline de título automático renomear);
- Uma sessão nova começa dentro desse tópico;
- Sua resposta é publicada nesse tópico.
Em outras palavras, o chat raiz deixa de ser um lobby e vira uma porta: uma mensagem perdida, uma sala novinha.
O que nunca é movido
Este interruptor trata exatamente um caso — uma pessoa digitando uma mensagem comum na DM raiz. Todo o resto fica como está, por design:
- Slash commands não são movidos. Um
/statusdigitado na raiz continua sendo comando de lobby e nunca cria tópico. - Wakes internos e eventos roteados não são movidos. Disparos de cron, eventos roteados de outras plataformas e tarefas em background nunca são empurrados para um tópico novo.
- Tráfego que não é DM fica intocado. Grupos e canais não têm nada a ver com o modo de tópicos.
- Remetentes não autorizados não são movidos. A checagem de autorização acontece na etapa de lobby.
- Uma criação de tópico que falha cai no fallback. Se o Threaded Mode foi desligado no BotFather, a criação falha e o Hermes volta ao padrão: responder no seu tópico mais recentemente ativo em vez de descartar a mensagem.
Um detalhe de implementação vale saber: a transferência roda na entrada do adaptador, antes da geração da chave de sessão (ela mora em telegram_topic_transfer.py, dentro do plugin do Telegram). Assim o turno, a sessão dele e a resposta usam todos o tópico novo — você nunca fica com uma sessão numa thread e a resposta em outra.
Duas pequenas armadilhas
Primeiro, a resposta de abertura num tópico novo não tem âncora de resposta. Sua mensagem original vive fora do tópico, e o Telegram não deixa uma resposta atravessar para dentro dele, então o Hermes envia apenas por message_thread_id, sem âncora de resposta. Parece que a resposta não se prendeu à sua mensagem; o conteúdo está no tópico novo, e isso é esperado.
Segundo, em setups multi-bot a chave é lida por bot. Se um gateway serve vários bots do Telegram (um assistente pessoal, um bot de time), o interruptor é lido a partir de quem recebeu a mensagem, não do bot de lançamento. Vale lembrar quando você roda vários profiles atrás de um gateway e assume que mudar o profile default cobre tudo.
Uma delicadeza relacionada: renomeação automática de tópico. Assim que o Hermes gera um título de sessão, ele renomeia o tópico do Telegram na medida do possível para combinar — “New Topic” vira “Database migration plan”. Falhas apenas entram no log; a sessão não é afetada. Se você nomeia tópicos à mão e quer que fiquem como estão, a documentação cobre como desligar isso.
Quando vale ligar, e quando não vale
Vale se o Telegram é a sua bancada de trabalho multi-thread: um tópico por assunto, e você costuma entrar no chat pela tela inicial do app. Cada mensagem virando um tópico próprio impõe “thread nova, contexto novo”, que geralmente é o que você queria.
Não vale se você tem basicamente uma conversa rodando e só usa tópicos de vez em quando. Aí cada mensagem na raiz adiciona mais uma thread, e até o título automático alcançar você vai ver uma parede de “Hermes Chat”.
Se o que você realmente quer entender é a fronteira entre tópico, sessão e contexto, o guia de limites de sessão do site mapeia isso. O post do seletor inline do Telegram cobre como escolher modelos e sessões de dentro do chat, e DMs bot a bot entre pares é a outra metade da história do Telegram. Começando do zero? O guia de instalação tem a base de configuração de plataformas.
A versão curta
dm_topic_auto_transfer é um interruptor minúsculo que responde a uma pergunta bem concreta: “de qual conversa essa mensagem perdida fazia parte?”. A resposta antiga era “da última”; a nova é “de uma nova”. Manter o comportamento antigo como padrão está certo — a maioria das pessoas não quer um tópico por mensagem — mas para quem trata o Telegram como bancada de trabalho, ligar isso elimina uma classe inteira de contexto contaminado entre conversas.