본문으로 건너뛰기

WeCom (Enterprise WeChat)

Hermes를 Tencent의 enterprise messaging platform인 WeCom(企业微信)에 연결합니다. adapter는 WeCom의 AI Bot WebSocket gateway를 사용해 realtime bidirectional communication을 제공합니다. public endpoint나 webhook은 필요 없습니다.

prerequisites

  • WeCom organization account
  • WeCom Admin Console에서 만든 AI Bot
  • bot credential page의 Bot ID와 Secret
  • Python package: aiohttp, httpx

setup

Step 1: AI Bot 만들기

hermes gateway setup

WeCom을 선택하고 WeCom mobile app으로 QR code를 scan합니다. Hermes가 올바른 permission을 가진 bot application을 자동 생성하고 credential을 저장합니다.

setup wizard가 하는 일:

  1. terminal에 QR code 표시
  2. WeCom mobile app으로 scan할 때까지 대기
  3. Bot ID와 Secret 자동 retrieval
  4. access control configuration 안내

대안: manual setup

scan-to-create를 사용할 수 없으면 wizard가 manual input으로 fallback합니다.

  1. WeCom Admin Console에 로그인합니다.
  2. ApplicationsCreate ApplicationAI Bot으로 이동합니다.
  3. bot name과 description을 설정합니다.
  4. credential page에서 Bot IDSecret을 copy합니다.
  5. hermes gateway setup을 실행하고 WeCom을 선택한 뒤 prompt가 나오면 credential을 입력합니다.
경고

Bot Secret은 비공개로 유지하세요. 이 값을 가진 사람은 bot을 impersonate할 수 있습니다.

Step 2: Hermes 설정

hermes gateway setup

WeCom을 선택하고 prompt를 따릅니다. wizard가 다음을 안내합니다.

  • bot credential(QR scan 또는 manual entry)
  • access control setting(allowlist, pairing mode, open access)
  • cron/notification용 home channel

Option B: manual configuration

~/.hermes/.env에 다음을 추가합니다.

WECOM_BOT_ID=your-bot-id
WECOM_SECRET=your-secret

# Optional: restrict access
WECOM_ALLOWED_USERS=user_id_1,user_id_2

# Optional: home channel for cron/notifications
WECOM_HOME_CHANNEL=chat_id

Step 3: gateway 시작

hermes gateway

features

  • WebSocket transport - persistent connection, public endpoint 필요 없음
  • DM and group messaging - configurable access policy
  • Per-group sender allowlists - group별로 interaction 가능 sender를 세밀하게 제어
  • Media support - image, file, voice, video upload/download
  • AES-encrypted media - inbound attachment 자동 decrypt
  • Quote context - reply threading 보존
  • Markdown rendering - rich text response
  • Reply-mode streaming - inbound message context에 response를 correlate
  • Auto-reconnect - connection drop 시 exponential backoff

configuration options

config.yamlplatforms.wecom.extra 아래에 설정합니다.

KeyDefaultDescription
bot_idWeCom AI Bot ID(required)
secretWeCom AI Bot Secret(required)
websocket_urlwss://openws.work.weixin.qq.comWebSocket gateway URL
dm_policyopenDM access: open, allowlist, disabled, pairing
group_policyopenGroup access: open, allowlist, disabled
allow_from[]DM 허용 user ID(dm_policy=allowlist일 때)
group_allow_from[]허용 group ID(group_policy=allowlist일 때)
groups{}group별 configuration(아래 참고)

access policies

DM policy

bot에게 direct message를 보낼 수 있는 사람을 제어합니다.

ValueBehavior
open누구나 bot에게 DM 가능(기본값)
allowlistallow_from에 있는 user ID만 DM 가능
disabled모든 DM 무시
pairinginitial setup용 pairing mode
WECOM_DM_POLICY=allowlist

group policy

bot이 어느 group에서 respond할지 제어합니다.

ValueBehavior
open모든 group에서 respond(기본값)
allowlistgroup_allow_from에 listed된 group ID에서만 respond
disabled모든 group message 무시
WECOM_GROUP_POLICY=allowlist

per-group sender allowlists

세밀한 제어를 위해 특정 group 안에서 어떤 user가 bot과 상호작용할 수 있는지 제한할 수 있습니다. config.yaml에 설정합니다.

platforms:
wecom:
enabled: true
extra:
bot_id: "your-bot-id"
secret: "your-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"

동작 방식:

  1. group_policygroup_allow_from이 group 자체가 허용되는지 결정합니다.
  2. group이 top-level check를 통과하면, groups.<group_id>.allow_from list가 있을 때 그 group 안에서 상호작용할 수 있는 sender를 추가로 제한합니다.
  3. wildcard "*" group entry는 명시적으로 나열되지 않은 group의 default 역할을 합니다.
  4. allowlist entry는 모든 user를 허용하는 * wildcard를 지원하며, case-insensitive입니다.
  5. entry는 선택적으로 wecom:user: 또는 wecom:group: prefix format을 사용할 수 있습니다. prefix는 자동으로 제거됩니다.

group에 allow_from이 설정되어 있지 않으면, group 자체가 top-level policy check를 통과했다는 전제에서 해당 group의 모든 user가 허용됩니다.

media support

inbound(receiving)

adapter는 user의 media attachment를 받아 agent processing을 위해 local에 cache합니다.

Type처리 방식
Imagesdownload 후 local cache. URL-based 및 base64-encoded image 모두 지원
Filesdownload 후 cache. original message의 filename 보존
Voice사용 가능한 경우 voice message text transcription 추출
Mixed messagesWeCom mixed-type message(text + images)를 parse하고 모든 component 추출

Quoted messages: quoted(replied-to) message의 media도 추출되므로 agent는 사용자가 무엇에 reply하는지 context를 갖습니다.

AES-encrypted media decryption

WeCom은 일부 inbound media attachment를 AES-256-CBC로 encrypt합니다. adapter가 이를 자동 처리합니다.

  • inbound media item에 aeskey field가 있으면 adapter가 encrypted bytes를 download하고 AES-256-CBC + PKCS#7 padding으로 decrypt합니다.
  • AES key는 aeskey field를 base64-decode한 값입니다. 정확히 32 bytes여야 합니다.
  • IV는 key의 첫 16 bytes에서 파생됩니다.
  • cryptography Python package가 필요합니다. (pip install cryptography)

별도 configuration은 필요 없습니다. encrypted media가 오면 transparent하게 decrypt됩니다.

outbound(sending)

MethodWhat it sendsSize limit
sendMarkdown text messages4000 chars
send_image / send_image_filenative image messages10 MB
send_documentfile attachments20 MB
send_voicevoice messages(native voice는 AMR format only)2 MB
send_videovideo messages10 MB

Chunked upload: file은 512KB chunk로 3-step protocol(init → chunks → finish)을 통해 upload됩니다. adapter가 자동으로 처리합니다.

Automatic downgrade: media가 native type size limit을 넘지만 absolute 20MB file limit 아래라면 generic file attachment로 자동 전송됩니다.

  • Images > 10 MB → file로 전송
  • Videos > 10 MB → file로 전송
  • Voice > 2 MB → file로 전송
  • Non-AMR audio → file로 전송(WeCom native voice는 AMR만 지원)

absolute 20MB limit을 넘는 file은 거부되며 chat에 안내 message가 전송됩니다.

reply-mode stream responses

bot이 WeCom callback으로 message를 받으면 adapter는 inbound request ID를 기억합니다. request context가 아직 active인 동안 response가 전송되면 adapter는 WeCom reply-mode(aibot_respond_msg)와 streaming을 사용해 response를 inbound message에 직접 correlate합니다. WeCom client에서 더 자연스러운 대화 경험을 제공합니다.

inbound request context가 만료되었거나 사용할 수 없으면 adapter는 aibot_send_msg를 통한 proactive message sending으로 fallback합니다.

reply-mode는 media에도 동작합니다. uploaded media를 originating message에 대한 reply로 보낼 수 있습니다.

connection and reconnection

adapter는 WeCom gateway wss://openws.work.weixin.qq.com에 persistent WebSocket connection을 유지합니다.

connection lifecycle

  1. Connect: WebSocket connection을 열고 bot_id와 secret이 담긴 aibot_subscribe authentication frame을 보냅니다.
  2. Heartbeat: connection 유지를 위해 30초마다 application-level ping frame을 보냅니다.
  3. Listen: inbound frame을 계속 읽고 message callback을 dispatch합니다.

reconnection behavior

connection loss가 발생하면 adapter는 exponential backoff로 reconnect합니다.

AttemptDelay
1st retry2 seconds
2nd retry5 seconds
3rd retry10 seconds
4th retry30 seconds
5th+ retry60 seconds

reconnection이 성공할 때마다 backoff counter는 0으로 reset됩니다. disconnect 시 pending request future는 모두 fail 처리되어 caller가 무기한 hang되지 않습니다.

deduplication

inbound message는 message ID로 deduplicate됩니다. window는 5분이고 cache 최대 크기는 1000 entries입니다. reconnection이나 network hiccup 중 message가 두 번 처리되는 것을 막습니다.

all environment variables

VariableRequiredDefaultDescription
WECOM_BOT_IDWeCom AI Bot ID
WECOM_SECRETWeCom AI Bot Secret
WECOM_ALLOWED_USERS(empty)gateway-level allowlist용 comma-separated user IDs
WECOM_HOME_CHANNELcron/notification output용 Chat ID
WECOM_WEBSOCKET_URLwss://openws.work.weixin.qq.comWebSocket gateway URL
WECOM_DM_POLICYopenDM access policy
WECOM_GROUP_POLICYopengroup access policy

troubleshooting

ProblemFix
WECOM_BOT_ID and WECOM_SECRET are requiredenv var 둘 다 설정하거나 setup wizard에서 configure
WeCom startup failed: aiohttp not installedaiohttp 설치: pip install aiohttp
WeCom startup failed: httpx not installedhttpx 설치: pip install httpx
invalid secret (errcode=40013)secret이 bot credential과 일치하는지 확인
Timed out waiting for subscribe acknowledgementopenws.work.weixin.qq.com network connectivity 확인
Bot doesn't respond in groupsgroup_policy setting과 group ID가 group_allow_from에 있는지 확인
Bot ignores certain users in a groupgroups config section의 per-group allow_from list 확인
Media decryption failscryptography 설치: pip install cryptography
cryptography is required for WeCom media decryptioninbound media가 AES-encrypted입니다. 설치: pip install cryptography
Voice messages sent as filesWeCom native voice는 AMR format만 지원합니다. 다른 format은 file로 auto-downgrade됩니다.
File too large errorWeCom은 모든 file upload에 20MB absolute limit이 있습니다. file을 compress하거나 split하세요.
Images sent as files10MB 초과 image는 native image limit을 넘어 file attachment로 auto-downgrade됩니다.
Timeout sending message to WeComWebSocket이 disconnect되었을 수 있습니다. reconnection log를 확인하세요.
WeCom websocket closed during authenticationnetwork issue 또는 잘못된 credential입니다. bot_id와 secret을 확인하세요.