Documentação oficial desta página · v0.20.6
Hermes Relay (Conector)
O Relay é experimental. O contrato de comunicação, o esquema de autenticação e a configuração podem mudar sem ciclo de depreciação enquanto o sistema está sendo validado.
O Hermes Relay não é uma plataforma de conversa: é um sistema de conectores que deixa o seu gateway atender uma ou mais plataformas de mensagens reais (Discord, Telegram, Slack, WhatsApp, …) sem guardar nenhuma credencial de plataforma. Um serviço separado, o conector, é dono dos tokens de bot e dos sockets das plataformas. Seu gateway disca para fora, até o conector, por um único WebSocket autenticado, recebe um descritor de capacidades no handshake e passa a trocar por esse socket eventos de mensagem normalizados (entrada) e ações (saída).
Propriedades principais:
- Rede só de saída. O gateway nunca abre uma porta de entrada. As mensagens recebidas voltam pelo mesmo WebSocket que o gateway discou, então o relay funciona atrás de NAT e em máquinas sem IP público.
- Nenhum segredo de plataforma no gateway. Os tokens de bot vivem no conector. URLs de mídia protegidas por autenticação são re-hospedadas do lado do conector, então credenciais de plataforma nunca trafegam.
- Agnóstico de plataforma. O gateway descobre o que a plataforma atendida sabe fazer (limite de tamanho de mensagem, dialeto de markdown, suporte a edição/thread/streaming e o conjunto exato de operações suportadas) pelo descritor do handshake, não por lógica de plataforma escrita no código.
A interface formal entre gateway e conector está no repositório, em
docs/relay-connector-contract.md.
Quando usar o Relay
O Relay serve para implantações em que um serviço conector hospedado ou compartilhado cuida do lado da plataforma — por exemplo, hospedagem multi-inquilino em que um bot compartilhado atende os agentes de vários usuários, ou cenários em que você não quer tokens de bot na máquina do gateway. Se você roda seus próprios bots diretamente, use os adaptadores nativos de plataforma (Telegram, Discord etc.).
Inscrição
Um gateway auto-hospedado se autentica no conector com um segredo próprio. O comando
hermes gateway enroll troca um token de inscrição de uso único (emitido pelo conector quando
a rota do seu inquilino é provisionada e entregue junto com a configuração do gateway) por esse
segredo:
hermes gateway enroll \
--token <token-de-inscricao> \
--connector-url wss://connector.exemplo.com/relay
O que ele faz:
- Resolve um token de acesso novo do Nous Portal a partir do seu login existente
(
~/.hermes/auth.json) — isso prova qual organização (inquilino) da Nous é sua. Segateway.idp.token_urlestiver configurado, o seu próprio IdP é usado no lugar (o caminho air-gapped / IdP auto-hospedado, sem Nous Portal): comclient_id/client_secretconfigurados, ele faz um grant OAuth2 genérico de client-credentials; sem nenhum dos dois, a URL é tratada como um endpoint de token ambiente (um GET simples cujo corpo da resposta é o token — o padrão de servidor de metadados, por exemplo o$DOMINO_API_PROXY/access-tokenda Domino). Configurar só uma das duas credenciais é erro. - Envia por POST o token de inscrição e um id de gateway ao endpoint
/relay/enrolldo conector, sobre TLS. - O conector verifica o token (assinatura, uso único, inquilino correspondente), gera um segredo por gateway e uma chave de entrega por inquilino, e os devolve uma única vez.
- Grava as credenciais em
~/.hermes/.env:GATEWAY_RELAY_ID,GATEWAY_RELAY_SECRET,GATEWAY_RELAY_DELIVERY_KEY(maisGATEWAY_RELAY_URL/GATEWAY_RELAY_WAKE_URLquando fornecidos).
Reinicie o gateway depois para ele pegar o novo ambiente.
Opções:
| Opção | Descrição |
|---|---|
--token | O token de inscrição de uso único. Também pode vir de GATEWAY_RELAY_ENROLL_TOKEN. |
--connector-url | URL base ou de relay do conector (wss://…/relay ou https://…). Também pode vir de GATEWAY_RELAY_URL ou de gateway.relay_url no config.yaml. |
--gateway-id | Id estável desta instância de gateway (usado para granularidade do interruptor de emergência). Padrão: gw-<hostname>. |
--wake-url | URL opcional e alcançável que o conector cutuca (GET sem corpo) para acordar este gateway quando chega trabalho em buffer e ele está ocioso. Persistida como GATEWAY_RELAY_WAKE_URL. Sem ela, o gateway ainda drena as mensagens em buffer na próxima reconexão. |
O hermes gateway enroll se recusa a rodar em instalações gerenciadas/hospedadas — nelas a
plataforma de hospedagem provisiona o segredo de relay direto no ambiente do contêiner.
Configuração
O relay é ativado quando uma URL de relay do conector está configurada — não existe um sinalizador de recurso separado. Implantações que não a definem não são afetadas.
| Ajuste | Onde | Significado |
|---|---|---|
GATEWAY_RELAY_URL | env (~/.hermes/.env) | URL WebSocket de relay do conector. A presença dela habilita a plataforma de relay. |
gateway.relay_url | config.yaml | O mesmo que acima, na forma de arquivo de configuração (o env tem precedência). |
GATEWAY_RELAY_ID | env | Id desta instância de gateway (escrito pelo enroll). |
GATEWAY_RELAY_SECRET | env | Segredo por gateway que autentica o upgrade do WebSocket (escrito pelo enroll). |
GATEWAY_RELAY_DELIVERY_KEY | env | Chave de entrega por inquilino (escrita pelo enroll; mantida por compatibilidade futura). |
GATEWAY_RELAY_WAKE_URL / gateway.relay_wake_url | env / config.yaml | Alvo opcional de cutucada para acordar gateways ociosos/suspensos. |
GATEWAY_RELAY_PLATFORMS | env | Lista separada por vírgulas das plataformas que este gateway atende por uma única conexão (por exemplo, discord,telegram). Normalmente é carimbada pela implantação/orquestrador. |
GATEWAY_RELAY_BOT_IDS | env | Mapa JSON de identidades de bot por plataforma, por exemplo {"discord": {"botId": "…"}}. Anda junto com GATEWAY_RELAY_PLATFORMS. |
gateway.idp.token_url | config.yaml | Quando definido, a inscrição/provisionamento autentica contra o seu próprio IdP em vez do Nous Portal: OAuth2 client-credentials quando gateway.idp.client_id/client_secret também estão definidos; caso contrário, um endpoint de token ambiente (GET simples devolvendo o token, cru ou como {"access_token": …}). |
Capacidades suportadas
O que de fato funciona por uma conexão de relay é negociado no handshake: o conector anuncia uma
lista supported_ops, e o gateway só usa operação que o conector anunciou explicitamente
(conectores antigos caem para o conjunto legado send/edit/typing/follow_up). Os
sinalizadores de capacidade por plataforma (streaming por edição, threads, streaming de rascunho,
dialeto de markdown, limite de tamanho de mensagem) também vêm do descritor do handshake. Sujeito a
essa negociação, o relay suporta:
- Mensagens de texto e streaming — envios, respostas e streaming progressivo por edição quando a plataforma atendida suporta editar mensagens; caso contrário, a saída degrada para uma mensagem por trecho.
- Mídia, nos dois sentidos — imagens, voz, áudio, vídeo e documentos de saída são enviados ao conector (ou referenciados por URL pública) e entregues pela via de upload nativa de cada plataforma, com legendas. Anexos recebidos viram arquivos locais para o agente; URLs de plataforma protegidas por autenticação são re-hospedadas do lado do conector, então credenciais de plataforma nunca chegam ao gateway. As re-hospedagens de mídia têm teto de 25 MB e expiram (cerca de 1 hora).
- Prompts interativos nativos — aprovações de execução, confirmações e perguntas de esclarecimento aparecem com controles nativos da plataforma (botões do Discord, teclados inline do Telegram, ações do Block Kit no Slack, mensagens de botão/lista do WhatsApp) em vez do fallback de texto numerado. Apertar um botão volta como resposta de prompt autenticada do usuário que realmente clicou, então os controles de autorização do gateway se aplicam exatamente como a uma resposta digitada. A expiração do prompt é imposta do lado do gateway.
- Ciclo de vida de reação de confirmação — as reações de status de processamento do bot (👀 enquanto trabalha, ✅/❌ ao concluir) funcionam pelo relay. Reações são de melhor esforço: uma reação que falha nunca derruba um turno.
- Ciclo de vida de threads — criar threads de repasse e renomear threads (inclusive renomeações
semânticas com título gerado por LLM) por operações abstratas de plataforma
thread_create/thread_rename, com uma proteção contra sobrescrita para que a renomeação manual de uma pessoa prevaleça. A disponibilidade depende da plataforma (threads do Slack não podem ser renomeadas; o WhatsApp não tem threads). - Indicadores de digitação — o gateway emite "digitando" (e "parou de digitar") pelo conector enquanto processa.
- Metadados de conversa — consultas
get_chat_infosão repassadas ao conector quando anunciadas. - Entrega em buffer e despertar — quando o gateway fica ocioso ou se desconecta, o conector guarda as mensagens recebidas de forma durável e as reproduz em ordem na reconexão (com confirmação, sem perda nem duplicação). Se uma URL de despertar estiver registrada, o conector a cutuca quando chega trabalho em buffer para um gateway dormindo.
Atender várias plataformas é suportado: um mesmo gateway pode atender várias plataformas (por exemplo, Discord e Telegram) por uma única conexão de relay, com cada mensagem de saída marcada com a plataforma de destino.
Solução de problemas
A inscrição falha com 401 — o conector não conseguiu verificar o seu token de identidade. Faça
login de novo com hermes auth add nous (ou hermes setup) e tente outra vez.
A inscrição falha com 403 — o token de inscrição é inválido, expirou, já foi usado ou pertence a outro inquilino. Tokens de inscrição são de uso único; peça um novo a quem provisionou a rota do seu inquilino.
"Could not reach the connector" — confira a URL do conector. Você pode colar tanto a URL de
discagem wss://…/relay quanto a URL base https://…; a CLI converte uma na outra automaticamente.
O enroll se recusa a rodar — você está em uma instalação gerenciada/hospedada, onde o segredo
de relay é provisionado pela plataforma de hospedagem. A auto-inscrição só existe para gateways
auto-hospedados.
A plataforma de relay aparece desabilitada depois de já ter funcionado — um fechamento de WebSocket com código 4401 depois de um handshake bem-sucedido significa que o segredo do gateway foi revogado (por exemplo, a instância foi desprovisionada). O gateway para de reconectar de propósito e reporta o relay como desabilitado em vez de insistir. Um 4401 antes de qualquer handshake bem-sucedido é tratado como corrida transitória de "ainda não provisionado" e é repetido normalmente.
Nada mudou depois da inscrição — o gateway lê as GATEWAY_RELAY_* na inicialização. Reinicie-o
(hermes gateway restart).
Um recurso (botões, mídia, threads…) degrada silenciosamente para texto puro — o conector da sua
plataforma não anunciou aquela operação no supported_ops do handshake. O gateway cai de propósito
para o comportamento em texto em vez de mandar uma operação que o conector não sabe tratar.