Documentação oficial desta página · v0.20.6
Configuração do Google Chat
Conecte o Hermes Agent ao Google Chat como um bot. A integração usa assinaturas do tipo pull do Cloud Pub/Sub para os eventos de entrada e a API REST do Chat para as mensagens de saída. A ergonomia é equivalente à do Socket Mode do Slack ou ao long-polling do Telegram: o seu processo do Hermes não precisa de URL pública, nem de túnel, nem de certificado TLS. Ele conecta, autentica e escuta em uma assinatura — do mesmo jeito que um bot do Telegram escuta com um token.
Rode
hermes gateway setupe escolha Google Chat para um passo a passo guiado.
O Google Chat faz parte do Google Workspace. Você pode usar esta integração com um
Workspace pessoal (@seudominio.com registrado pelo Google) ou com um Workspace de
trabalho no qual você tenha direitos de administrador para publicar um aplicativo.
Contas apenas de Gmail não podem hospedar aplicativos do Chat.
Visão geral
| Componente | Valor |
|---|---|
| Bibliotecas | google-cloud-pubsub, google-api-python-client, google-auth |
| Transporte de entrada | Assinatura pull do Cloud Pub/Sub (sem endpoint público) |
| Transporte de saída | API REST do Chat (chat.googleapis.com) |
| Autenticação | JSON de conta de serviço com roles/pubsub.subscriber na assinatura |
| Identificação de usuário | Nomes de recurso do Chat (users/{id}) + e-mail |
Passo 1: Crie ou escolha um projeto do GCP
Você precisa de um projeto do Google Cloud para hospedar o tópico do Pub/Sub. Se não tem um, crie em console.cloud.google.com — contas pessoais ganham uma camada gratuita que cobre com folga o tráfego de um bot.
Anote o ID do projeto (por exemplo, my-chat-bot-123). Você vai usá-lo em todo passo
seguinte.
Passo 2: Habilite duas APIs
No console, vá em APIs & Services → Library e habilite:
- Google Chat API
- Cloud Pub/Sub API
As duas são gratuitas nos volumes que um bot pessoal gera.
Passo 3: Crie uma conta de serviço
IAM & Admin → Service Accounts → Create Service Account.
- Nome:
hermes-chat-bot - Pule a etapa "Grant this service account access to project". O IAM na assinatura específica é tudo de que você precisa — NÃO conceda papéis de Pub/Sub no nível do projeto.
Depois de criar, abra a conta de serviço, vá em Keys → Add Key → Create new key → JSON e
baixe o arquivo. Guarde-o em um lugar que só o Hermes consiga ler (por exemplo,
~/.hermes/google-chat-sa.json, com chmod 600).
Um erro comum é procurar por um papel de IAM específico do Chat e concedê-lo no nível do projeto. Esse papel não existe. A autoridade de um bot do Chat vem de ele estar instalado em um espaço, não do IAM. Tudo de que a sua conta de serviço precisa é ser Pub/Sub subscriber na assinatura que você cria no passo seguinte.
Passo 4: Crie o tópico e a assinatura do Pub/Sub
Pub/Sub → Topics → Create topic.
- ID do tópico:
hermes-chat-events - Deixe todo o resto no padrão.
Depois de criar, a página de detalhes do tópico tem uma aba Subscriptions. Crie uma:
- ID da assinatura:
hermes-chat-events-sub - Tipo de entrega: Pull
- Retenção de mensagens: 7 dias (para a fila sobreviver a um reinício do hermes)
- Deixe o resto no padrão.
Passo 5: Vínculo de IAM no tópico (crítico)
No tópico (não na assinatura), acrescente um principal de IAM:
- Principal:
chat-api-push@system.gserviceaccount.com - Papel:
Pub/Sub Publisher
Sem isso, o Google Chat não consegue publicar eventos no seu tópico e o seu bot nunca vai receber nada.
Passo 6: Vínculo de IAM na assinatura
Na assinatura, acrescente a sua própria conta de serviço como principal:
- Principal:
hermes-chat-bot@<seu-projeto>.iam.gserviceaccount.com - Papel:
Pub/Sub Subscriber
Conceda também Pub/Sub Viewer na mesma assinatura — o Hermes chama
subscription.get() ao subir, como checagem de alcançabilidade.
Passo 7: Configure o aplicativo do Chat
Vá em APIs & Services → Google Chat API → Configuration.
- App name: o que você quiser que os usuários vejam ("Hermes" é razoável).
- Avatar URL: qualquer PNG público (o Google tem alguns padrões).
- Description: uma frase curta, mostrada no diretório de aplicativos.
- Functionality: habilite Receive 1:1 messages e Join spaces and group conversations.
- Connection settings: escolha Cloud Pub/Sub e informe o nome do tópico
projects/<seu-projeto>/topics/hermes-chat-events. - Visibility: restrinja ao seu workspace (ou a usuários específicos) — não publique para todo mundo enquanto estiver testando.
Salve.
Passo 8: Instale o bot em um espaço de teste
Abra o Google Chat em um navegador. Comece uma conversa direta com o seu aplicativo
procurando pelo nome dele no menu + New Chat. Na primeira vez que você mandar
mensagem, o Google envia um evento ADDED_TO_SPACE que o Hermes usa para guardar o
próprio users/{id} do bot, para filtrar as mensagens dele mesmo.
Passo 9: Configure o Hermes
Acrescente a seção do Google Chat ao ~/.hermes/.env:
# Obrigatório
GOOGLE_CHAT_PROJECT_ID=my-chat-bot-123
GOOGLE_CHAT_SUBSCRIPTION_NAME=projects/my-chat-bot-123/subscriptions/hermes-chat-events-sub
GOOGLE_CHAT_SERVICE_ACCOUNT_JSON=/home/voce/.hermes/google-chat-sa.json
# Autorização — cole os e-mails das pessoas que podem falar com o bot
GOOGLE_CHAT_ALLOWED_USERS=voce@seudominio.com,colega@seudominio.com
# Opcional
GOOGLE_CHAT_HOME_CHANNEL=spaces/AAAA... # destino de entrega padrão para jobs de cron
GOOGLE_CHAT_MAX_MESSAGES=1 # FlowControl do Pub/Sub; 1 serializa os comandos por sessão
GOOGLE_CHAT_MAX_BYTES=16777216 # 16 MiB — teto de bytes de mensagem em trânsito
O ID do projeto também recai em GOOGLE_CLOUD_PROJECT, e o caminho da conta de serviço
recai em GOOGLE_APPLICATION_CREDENTIALS — use a convenção que preferir.
Instale as dependências do adaptador do Google Chat pelo instalador mantido dele. Ele aplica os mesmos pisos de segurança fixados que as checagens de execução usam:
python -m plugins.platforms.google_chat.oauth --install-deps
Suba o gateway:
hermes gateway
Você deve ver uma linha de log assim:
[GoogleChat] Connected; project=my-chat-bot-123, subscription=<redacted>,
bot_user_id=users/XXXX, flow_control(msgs=1, bytes=16777216)
Mande "olá" na conversa de teste. O bot publica um marcador "Hermes is thinking…" e depois edita essa mesma mensagem no lugar com a resposta de verdade — sem lápides de "mensagem apagada".
Personalizar o marcador de estado de trabalho
O texto do marcador é configurável por typing_status_text no
~/.hermes/config.yaml — por exemplo, uma assistente gatinha chamada Ada:
platforms:
google_chat:
# Texto personalizado do marcador de estado de trabalho (padrão: "Hermes is thinking…").
typing_status_text: "está dando um pulo… 🐾"
Diferente da linha de status efêmera do Slack, esta é uma mensagem publicada de
verdade, que é editada no lugar com a resposta — então o que você colocar aqui
aparece por um instante na conversa como uma mensagem normal. Defina
typing_indicator: false para desligar o marcador de vez.
Formatação e capacidades
O Google Chat renderiza um subconjunto limitado de markdown:
| Suportado | Não suportado |
|---|---|
*negrito*, _itálico_, ~riscado~, `código` | Títulos, listas |
| Imagens embutidas por URL | Botões interativos de Card v2 (na v1 deste gateway) |
Anexos nativos de arquivo (depois do /setup-files — veja o Passo 10) | Notas de voz nativas / notas de vídeo circulares |
O prompt de sistema do agente inclui uma dica específica do Google Chat, para que ele conheça esses limites e evite formatação que não vai aparecer.
Limite de tamanho da mensagem: 4000 caracteres por mensagem. Respostas mais longas do agente são divididas automaticamente em várias mensagens.
Suporte a conversas encadeadas: quando um usuário responde dentro de uma thread, o
Hermes detecta o thread.name e publica a resposta na mesma thread, então cada thread
ganha uma sessão separada do Hermes.
Perguntas de esclarecimento como cards interativos
Quando o agente faz uma pergunta de esclarecimento de múltipla escolha, o adaptador a
renderiza como um Card v2 nativo, com um botão por opção mais um botão
"Other / type answer", em vez de uma lista numerada em texto puro.
Clicar em um botão responde à pergunta direto (eventos CARD_CLICKED levam a escolha
de volta para a sessão que está esperando). Se o card falhar ao ser enviado, ou se a
pergunta não tiver opções fixas, o adaptador recai no esclarecimento padrão em texto.
Não precisa configurar nada.
Passo 10: Entrega nativa de anexos (opcional)
Sem nenhuma configuração extra, o bot consegue publicar texto, imagens embutidas por URL e cards de download para áudio, vídeo e documentos. Para entregar anexos nativos do Chat — o mesmo widget de arquivo que aparece quando uma pessoa arrasta e solta um arquivo — cada usuário autoriza o bot uma vez, por um fluxo de OAuth individual.
Por que um fluxo separado
O endpoint media.upload do Google Chat recusa de forma categórica a autenticação por
conta de serviço:
This method doesn't support app authentication with a service account. Authenticate with a user account.
Não existe papel de IAM nem escopo que resolva isso. O endpoint só aceita credenciais de usuário. Então o bot tem que agir como um usuário sempre que envia um arquivo — mais precisamente, como o usuário que pediu o arquivo.
Configuração única (por perfil)
- Vá em APIs & Services → Credentials no mesmo projeto do GCP.
- Create credentials → OAuth client ID → Desktop app.
- Baixe o JSON. Mova-o para a máquina que roda o Hermes.
- Registre o cliente no Hermes (rode sob o perfil ao qual você quer restringi-lo):
# Perfil padrão:
python -m plugins.platforms.google_chat.oauth \
--client-secret /caminho/do/client_secret.json
# Um perfil nomeado ganha o próprio registro, separado:
hermes -p <profile> python -m plugins.platforms.google_chat.oauth \
--client-secret /caminho/do/client_secret.json
Isso escreve o segredo de cliente no diretório do Hermes do perfil ativo (por exemplo,
~/.hermes/google_chat_user_client_secret.json para o perfil padrão). O segredo de
cliente é restrito ao perfil, não compartilhado entre perfis — cada perfil registra
o seu. Isso é de propósito: perfis são fronteiras isoladas de autenticação, então dois
perfis podem apontar para aplicativos/contas de OAuth diferentes do Google. Registre uma
vez por perfil que precisar de entrega de anexos pelo Google Chat.
Autorização por usuário (na conversa)
Cada usuário roda o fluxo uma vez, na própria conversa direta com o bot:
- A pessoa manda
/setup-filesao bot. Ele responde com o status e o próximo passo. - Ela manda
/setup-files start. O bot responde com uma URL de OAuth. - Ela abre a URL, clica em Allow e vê o navegador falhar em carregar
http://localhost:1/?...&code=.... Essa falha é esperada — o código de autorização está na barra de endereço. - Ela copia a URL que falhou (ou só o valor de
code=...) e cola de volta na conversa como/setup-files <PASTED_URL>. O bot troca isso por um refresh token.
O token vai para ~/.hermes/google_chat_user_tokens/<sanitized_email>.json.
Os pedidos de arquivo seguintes na conversa daquele usuário usam o token dele, então o
bot envia como ele e a mensagem cai no espaço dele.
Para revogar depois: /setup-files revoke apaga só o token daquele usuário. Os tokens
dos outros ficam intocados.
Escopo
O fluxo pede exatamente um escopo: chat.messages.create. Ele cobre tanto o
media.upload quanto o messages.create que referencia o attachmentDataRef
enviado. Sem Drive, sem escopos mais amplos do Chat — isto é privilégio mínimo
de propósito.
Comportamento com vários usuários
Quando quem pediu ainda não tem token individual, o bot recai em um token legado de
usuário único em ~/.hermes/google_chat_user_token.json (se existir, de uma instalação
anterior ao suporte a vários usuários). Quando nenhum dos dois está disponível, o bot
publica um aviso claro em texto dizendo a quem pediu para rodar o /setup-files.
Um usuário que revoga limpa só a própria vaga. Um 401/403 do token de um usuário descarta só o cache daquele usuário. Os usuários não atrapalham uns aos outros.
Resolução de problemas
O bot fica calado depois que você manda "olá".
- Confira no console se a assinatura do Pub/Sub tem mensagens não entregues.
Se tiver, o Hermes não está autenticado — verifique o
GOOGLE_CHAT_SERVICE_ACCOUNT_JSONe se a conta de serviço está listada comoPub/Sub Subscriberna assinatura. - Se a assinatura está com zero mensagens, o Google Chat não está publicando.
Reveja o vínculo de IAM no tópico:
chat-api-push@system.gserviceaccount.comprecisa terPub/Sub Publisher. - Procure
[GoogleChat] Connectednos logs dohermes gateway. Se você vê[GoogleChat] Config validation failed, a mensagem de erro diz qual variável de ambiente corrigir.
O bot responde, mas aparece uma mensagem de erro no lugar da resposta do agente.
Procure [GoogleChat] Pub/Sub stream died nos logs — se isso se repete, as credenciais
da sua conta de serviço podem ter sido rotacionadas, ou a assinatura foi apagada. Depois
de 10 tentativas, o adaptador se marca como fatal.
"403 Forbidden" em toda mensagem de saída.
O bot foi removido do espaço, ou você o revogou no console da API do Chat.
Reinstale-o no espaço (o próximo evento ADDED_TO_SPACE reabilita as mensagens
automaticamente).
Avisos de "Rate limit hit" demais.
As cotas padrão da API do Chat permitem 60 mensagens por espaço por minuto. Se o seu agente produz respostas longas em streaming que passam disso, o adaptador tenta de novo com recuo exponencial — mas você ainda vai sentir latência visível. Considere respostas mais concisas ou aumentar a cota no console do GCP.
O bot fica publicando o aviso de "/setup-files" em vez dos arquivos.
Quem pediu não tem token de OAuth individual e não há plano B legado. Rode
/setup-files na conversa dessa pessoa e siga o Passo 10. Depois que a troca terminar,
o próximo pedido de arquivo já sobe nativamente, sem reiniciar o gateway.
O /setup-files start diz "No client credentials stored."
A configuração única não foi feita para este perfil (o segredo de cliente é restrito ao perfil, então um registro sob um perfil não é visto por outro). Em um terminal, rode-a sob o perfil que o gateway usa:
# Perfil padrão:
python -m plugins.platforms.google_chat.oauth \
--client-secret /caminho/do/client_secret.json
# Perfil nomeado:
hermes -p <profile> python -m plugins.platforms.google_chat.oauth \
--client-secret /caminho/do/client_secret.json
Depois mande /setup-files start de novo.
O /setup-files <PASTED_URL> diz "Token exchange failed."
O código de autorização é de uso único e tem vida curta (em geral alguns minutos). Mande
/setup-files start para pegar uma URL nova e tente outra vez.
Notas de segurança
- Escopo da conta de serviço: o adaptador pede os escopos
chat.botepubsub. O IAM é que deve ser a imposição de verdade — conceda à sua conta de serviço o mínimo (roles/pubsub.subscriber+roles/pubsub.viewerna assinatura), e não papéis de Pub/Sub no nível do projeto ou da organização. - Proteção no download de anexos: o Hermes só anexa o token bearer da conta de
serviço a URLs cujo host bate com uma lista curta de domínios do Google
(
googleapis.com,drive.google.com,lh[3-6].googleusercontent.come alguns outros). Qualquer outro host é recusado antes da requisição HTTP, para proteger contra cenários de SSRF em que um evento forjado poderia redirecionar o token bearer ao serviço de metadados do GCE. - Redação: e-mails de conta de serviço, caminhos de assinatura e caminhos de tópico
são removidos da saída de log pelo
agent/redact.py. O despejo de envelope de depuração (GOOGLE_CHAT_DEBUG_RAW=1) passa pelo mesmo filtro de redação e registra em nível DEBUG. - Conformidade: se você pretende ligar este bot a um workspace regulado (qualquer um com política de residência de dados ou de governança de IA), consiga essa aprovação antes da primeira instalação.
- Escopo de OAuth do usuário: o fluxo de anexos por usuário pede somente
chat.messages.create— o mínimo que cobre omedia.uploadmais omessages.createseguinte. Os tokens ficam gravados como JSON puro em~/.hermes/google_chat_user_tokens/<sanitized_email>.json(as permissões do sistema de arquivos são a proteção — o mesmo modelo do arquivo de chave da conta de serviço). Cada token pertence a exatamente um usuário; a revogação é restrita àquele usuário.