Documentação oficial desta página · v0.20.6
WeCom (WeChat Corporativo)
Conecte o Hermes ao WeCom (企业微信), a plataforma de mensagens corporativas da Tencent. O adaptador usa o gateway WebSocket de AI Bot do WeCom para comunicação bidirecional em tempo real — sem precisar de endpoint público nem de webhook.
Veja também: WeCom Callback para configurar o webhook de entrada.
Pré-requisitos
- Uma conta de organização no WeCom
- Um AI Bot criado no console de administração do WeCom
- O Bot ID e o Secret da página de credenciais do bot
- Pacotes Python:
aiohttpehttpx
Instalação
Passo 1: crie um AI Bot
Recomendado: criar por QR code (um comando)
hermes gateway setup
Escolha WeCom e leia o QR code com o aplicativo do WeCom no celular. O Hermes cria automaticamente uma aplicação de bot com as permissões certas e salva as credenciais.
O assistente de instalação vai:
- Mostrar um QR code no seu terminal
- Esperar você ler o código com o app do WeCom
- Buscar automaticamente o Bot ID e o Secret
- Guiar você pela configuração do controle de acesso
Alternativa: instalação manual
Se a criação por QR code não estiver disponível, o assistente cai para a entrada manual:
- Entre no console de administração do WeCom
- Vá em Aplicações → Criar aplicação → AI Bot
- Configure o nome e a descrição do bot
- Copie o Bot ID e o Secret da página de credenciais
- Rode
hermes gateway setup, escolha WeCom e informe as credenciais quando pedido
Mantenha o Bot Secret em segredo. Quem tem ele consegue se passar pelo seu bot.
Passo 2: configure o Hermes
Opção A: instalação interativa (recomendada)
hermes gateway setup
Escolha WeCom e siga as perguntas. O assistente guia você por:
- Credenciais do bot (por leitura de QR code ou entrada manual)
- Ajustes de controle de acesso (lista de permissão, modo de pareamento ou acesso aberto)
- Canal principal para notificações
Opção B: configuração manual
Acrescente o seguinte ao ~/.hermes/.env:
WECOM_BOT_ID=seu-bot-id
WECOM_SECRET=seu-secret
# Opcional: restringe o acesso
WECOM_ALLOWED_USERS=user_id_1,user_id_2
# Opcional: canal principal para cron/notificações
WECOM_HOME_CHANNEL=chat_id
Passo 3: suba o gateway
hermes gateway
Recursos
- Transporte por WebSocket — conexão persistente, sem precisar de endpoint público
- Mensagens diretas e em grupo — políticas de acesso configuráveis
- Listas de remetentes permitidos por grupo — controle fino de quem pode interagir em cada grupo
- Suporte a mídia — upload e download de imagens, arquivos, voz e vídeo
- Mídia criptografada em AES — descriptografia automática dos anexos de entrada
- Contexto de citação — preserva o encadeamento das respostas
- Renderização de Markdown — respostas com texto formatado
- Correlação de resposta — as respostas são correlacionadas ao contexto da mensagem de entrada
- Reconexão automática — recuo exponencial quando a conexão cai
O adaptador do WeCom transmite respostas nativamente pelo protocolo msgtype: "stream" do WeCom: o
cliente mostra um balão de "pensando/digitando" assim que o turno começa, e a resposta é renderizada
token a token num único balão, conforme o modelo gera. O progresso das chamadas de ferramenta entra
no mesmo balão. O streaming nativo vem ligado por padrão
(display.platforms.wecom.streaming: true no config.yaml); defina como false para voltar à
entrega de uma vez só.
Opções de configuração
Defina estas em config.yaml, sob platforms.wecom.extra:
| Chave | Padrão | Descrição |
|---|---|---|
bot_id | — | Bot ID do AI Bot do WeCom (obrigatório) |
secret | — | Secret do AI Bot do WeCom (obrigatório) |
websocket_url | wss://openws.work.weixin.qq.com | URL do gateway WebSocket |
dm_policy | open | Acesso por mensagem direta: open, allowlist, disabled, pairing |
group_policy | open | Acesso em grupo: open, allowlist, disabled |
allow_from | [] | IDs de usuário liberados para mensagem direta (quando dm_policy=allowlist) |
group_allow_from | [] | IDs de grupo liberados (quando group_policy=allowlist) |
groups | {} | Configuração por grupo (veja abaixo) |
stream_keepalive_enabled | false | Envia quadros periódicos de keepalive para renovar a janela de ~6 minutos do fluxo de resposta do WeCom em turnos longos |
stream_keepalive_interval_seconds | 120 | Cadência dos quadros de keepalive quando ligado |
stream_safe_duration_seconds | 330 | Idade do fluxo a partir da qual a finalização prefere o envio proativo, mais confiável |
Políticas de acesso
Política de mensagem direta
Controla quem pode mandar mensagem direta para o bot:
| Valor | Comportamento |
|---|---|
open | Qualquer um pode mandar mensagem direta (padrão) |
allowlist | Só os IDs de usuário em allow_from podem mandar |
disabled | Todas as mensagens diretas são ignoradas |
pairing | Modo de pareamento (para a configuração inicial) |
WECOM_DM_POLICY=allowlist
Política de grupo
Controla em quais grupos o bot responde:
| Valor | Comportamento |
|---|---|
open | O bot responde em todos os grupos (padrão) |
allowlist | O bot só responde nos IDs de grupo listados em group_allow_from |
disabled | Todas as mensagens de grupo são ignoradas |
WECOM_GROUP_POLICY=allowlist
Listas de remetentes permitidos por grupo
Para um controle mais fino, você pode restringir quais usuários podem interagir com o bot dentro de
grupos específicos. Isso é configurado no config.yaml:
platforms:
wecom:
enabled: true
extra:
bot_id: "seu-bot-id"
secret: "seu-secret"
group_policy: "allowlist"
group_allow_from:
- "group_id_1"
- "group_id_2"
groups:
group_id_1:
allow_from:
- "user_alice"
- "user_bob"
group_id_2:
allow_from:
- "user_charlie"
"*":
allow_from:
- "user_admin"
Como funciona:
- Os controles
group_policyegroup_allow_fromdeterminam se o grupo é permitido, para começar. - Se o grupo passa na checagem de topo, a lista
groups.<group_id>.allow_from(se existir) restringe ainda mais quais remetentes daquele grupo podem interagir com o bot. - Uma entrada de grupo curinga
"*"serve de padrão para os grupos que não estão listados explicitamente. - As entradas da lista aceitam o curinga
*para liberar todos os usuários, e não diferenciam maiúsculas de minúsculas. - As entradas podem, opcionalmente, usar o formato com prefixo
wecom:user:ouwecom:group:— o prefixo é removido automaticamente.
Se nenhum allow_from estiver configurado para um grupo, todos os usuários daquele grupo são
permitidos (supondo que o próprio grupo passe na checagem de política de topo).
Suporte a mídia
Entrada (recebimento)
O adaptador recebe anexos de mídia dos usuários e guarda em cache local para o agente processar:
| Tipo | Como é tratado |
|---|---|
| Imagens | Baixadas e guardadas em cache local. Aceita imagens por URL e codificadas em base64. |
| Arquivos | Baixados e guardados em cache. O nome do arquivo é preservado da mensagem original. |
| Voz | A transcrição em texto da mensagem de voz é extraída, quando disponível. |
| Mensagens mistas | Mensagens de tipo misto do WeCom (texto + imagens) são analisadas e todos os componentes extraídos. |
Mensagens citadas: a mídia de mensagens citadas (respondidas) também é extraída, para que o agente tenha contexto sobre o que o usuário está respondendo.
Descriptografia de mídia com AES
O WeCom criptografa alguns anexos de mídia de entrada com AES-256-CBC. O adaptador cuida disso automaticamente:
- Quando um item de mídia de entrada traz o campo
aeskey, o adaptador baixa os bytes criptografados e descriptografa com AES-256-CBC e padding PKCS#7. - A chave AES é o valor do campo
aeskeydecodificado de base64 (precisa ter exatamente 32 bytes). - O IV é derivado dos 16 primeiros bytes da chave.
- Isso exige o pacote Python
cryptography(pip install cryptography).
Não é preciso configurar nada — a descriptografia acontece de forma transparente quando chega mídia criptografada.
Saída (envio)
| Método | O que envia | Limite de tamanho |
|---|---|---|
send | Mensagens de texto em Markdown | 4000 caracteres |
send_image / send_image_file | Mensagens nativas de imagem | 10 MB |
send_document | Anexos de arquivo | 20 MB |
send_voice | Mensagens de voz (só formato AMR para voz nativa) | 2 MB |
send_video | Mensagens de vídeo | 10 MB |
Upload em pedaços: os arquivos são enviados em pedaços de 512 KB, por um protocolo de três etapas (init → pedaços → finish). O adaptador cuida disso automaticamente.
Rebaixamento automático: quando a mídia passa do limite de tamanho do tipo nativo mas fica abaixo do limite absoluto de 20 MB por arquivo, ela é enviada automaticamente como anexo de arquivo genérico:
- Imagens > 10 MB → enviadas como arquivo
- Vídeos > 10 MB → enviados como arquivo
- Voz > 2 MB → enviada como arquivo
- Áudio que não seja AMR → enviado como arquivo (o WeCom só aceita AMR para voz nativa)
Arquivos que passam do limite absoluto de 20 MB são recusados, com uma mensagem informativa enviada ao chat.
Respostas em modo de resposta
Quando o bot recebe uma mensagem pelo callback do WeCom, o adaptador guarda o ID da requisição de
entrada. Se uma resposta é enviada enquanto o contexto da requisição ainda está ativo, o adaptador
usa o modo de resposta do WeCom (aibot_respond_msg) para correlacionar a resposta diretamente à
mensagem de entrada. Isso deixa a conversa mais natural no cliente do WeCom.
Quando há um fluxo nativo de resposta ativo, a resposta é transmitida aos poucos por quadros
msgtype: "stream" em modo de resposta. Se o contexto da requisição de entrada expirou ou não está
disponível (ou se um quadro do fluxo falha), o adaptador cai para o envio proativo de mensagem, via
aibot_send_msg.
O modo de resposta também funciona para mídia: a mídia enviada pode ir como resposta à mensagem de origem.
Conexão e reconexão
O adaptador mantém uma conexão WebSocket persistente com o gateway do WeCom em
wss://openws.work.weixin.qq.com.
Ciclo de vida da conexão
- Conectar: abre uma conexão WebSocket e envia um quadro de autenticação
aibot_subscribecom o bot_id e o secret. - Heartbeat: envia quadros de ping no nível da aplicação a cada 30 segundos, para manter a conexão viva.
- Escutar: lê continuamente os quadros de entrada e despacha os callbacks de mensagem.
Comportamento de reconexão
Quando a conexão cai, o adaptador reconecta com recuo exponencial:
| Tentativa | Espera |
|---|---|
| 1ª tentativa | 2 segundos |
| 2ª tentativa | 5 segundos |
| 3ª tentativa | 10 segundos |
| 4ª tentativa | 30 segundos |
| 5ª tentativa em diante | 60 segundos |
Depois de cada reconexão bem-sucedida, o contador de recuo volta a zero. Todas as futures de requisição pendentes falham na desconexão, para que quem chamou não fique travado para sempre.
Deduplicação
As mensagens de entrada são deduplicadas por ID de mensagem, com uma janela de 5 minutos e cache máximo de 1000 entradas. Isso evita processar a mesma mensagem duas vezes durante reconexões ou soluços de rede.
Todas as variáveis de ambiente
| Variável | Obrigatória | Padrão | Descrição |
|---|---|---|---|
WECOM_BOT_ID | ✅ | — | Bot ID do AI Bot do WeCom |
WECOM_SECRET | ✅ | — | Secret do AI Bot do WeCom |
WECOM_ALLOWED_USERS | — | (vazio) | IDs de usuário separados por vírgula, para a lista de permissão no nível do gateway |
WECOM_HOME_CHANNEL | — | — | ID de chat para a saída de cron/notificações |
WECOM_WEBSOCKET_URL | — | wss://openws.work.weixin.qq.com | URL do gateway WebSocket |
WECOM_DM_POLICY | — | open | Política de acesso por mensagem direta |
WECOM_GROUP_POLICY | — | open | Política de acesso em grupo |
Resolução de problemas
| Problema | Solução |
|---|---|
WECOM_BOT_ID and WECOM_SECRET are required | Defina as duas variáveis de ambiente ou configure pelo assistente |
WeCom startup failed: aiohttp not installed | Instale o aiohttp: pip install aiohttp |
WeCom startup failed: httpx not installed | Instale o httpx: pip install httpx |
invalid secret (errcode=40013) | Confira se o secret bate com as credenciais do seu bot |
Timed out waiting for subscribe acknowledgement | Verifique a conectividade de rede com openws.work.weixin.qq.com |
| O bot não responde em grupos | Confira o ajuste group_policy e garanta que o ID do grupo está em group_allow_from |
| O bot ignora certos usuários num grupo | Confira as listas allow_from por grupo na seção groups da configuração |
| A descriptografia de mídia falha | Instale o cryptography: pip install cryptography |
cryptography is required for WeCom media decryption | A mídia de entrada está criptografada em AES. Instale: pip install cryptography |
| Mensagens de voz chegam como arquivos | O WeCom só aceita o formato AMR para voz nativa. Outros formatos são rebaixados automaticamente para arquivo. |
Erro File too large | O WeCom tem um limite absoluto de 20 MB para todo upload de arquivo. Comprima ou divida o arquivo. |
| Imagens chegam como arquivos | Imagens > 10 MB passam do limite nativo de imagem e são rebaixadas automaticamente para anexo de arquivo. |
Timeout sending message to WeCom | O WebSocket pode ter desconectado. Procure mensagens de reconexão nos logs. |
WeCom websocket closed during authentication | Problema de rede ou credenciais erradas. Confira o bot_id e o secret. |