hermes - 💡(How to fix) Fix [i18n] Thai Translation: Messaging Part e - webhooks, wecom, wecom-callback, weixin, whatsapp [1 participants]
ON THIS PAGE
Recommended Tools
×6Utilities matched from this issue’s tags and category — try them while you read without losing context.
GitHub issue graph ai analysis
Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.
The report is written in English Markdown for sharing and archival.
Helpful · Quick feedback
Error Message
- Keys ที่ขาดหายไปจะถูกทิ้งไว้เป็น string literal
{key}(ไม่มี error) |File too largeerror | WeCom มีขีดจำกัดสูงสุด 20 MB สำหรับการอัปโหลดไฟล์ทั้งหมด. ให้บีบอัดหรือแบ่งไฟล์ | | Transient error (1st–2nd) | Retry after 2 seconds | มีเพียง Weixin gateway instance เดียวเท่านั้นที่สามารถใช้ token ที่กำหนดได้ในเวลาใดเวลาหนึ่ง อะแดปเตอร์จะเข้าถึง scoped lock เมื่อเริ่มต้นและปล่อยเมื่อปิด หาก gateway อื่นกำลังใช้ token เดียวกันอยู่ การเริ่มต้นจะล้มเหลวพร้อมข้อความ error ที่ให้ข้อมูล
Fix Action
Fix / Workaround
- Connect: ตรวจสอบ credentials และเริ่ม poll loop
- Poll: เรียก
getupdatesด้วย timeout 35 วินาที; server จะคงคำขอไว้จนกว่าข้อความจะมาถึงหรือหมดเวลา - Dispatch: ข้อความขาเข้าจะถูก dispatch แบบ concurrent ผ่าน
asyncio.create_task - Sync buffer: sync cursor แบบถาวร (
get_updates_buf) จะถูกบันทึกใน disk เพื่อให้อะแดปเตอร์สามารถดำเนินการต่อจากตำแหน่งที่ถูกต้องหลังจากการรีสตาร์ท
Code Example
hermes gateway setup
---
WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644 # default
WEBHOOK_SECRET=your-global-secret
---
curl http://localhost:8644/health
---
{"status": "ok", "platform": "webhook"}
---
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-fallback-secret"
routes:
github-pr:
events: ["pull_request"]
secret: "github-webhook-secret"
prompt: |
Review this pull request:
Repository: {repository.full_name}
PR #{number}: {pull_request.title}
Author: {pull_request.user.login}
URL: {pull_request.html_url}
Diff URL: {pull_request.diff_url}
Action: {action}
skills: ["github-code-review"]
deliver: "github_comment"
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
deploy-notify:
events: ["push"]
secret: "deploy-secret"
prompt: "New push to {repository.full_name} branch {ref}: {head_commit.message}"
deliver: "telegram"
---
prompt: "PR #{pull_request.number} by {pull_request.user.login}: {__raw__}"
---
webhooks:
routes:
alerts:
events: ["alert"]
prompt: "Alert: {__raw__}"
deliver: "telegram"
deliver_extra:
chat_id: "-1001234567890"
message_thread_id: "42"
---
gh auth login
---
platforms:
webhook:
enabled: true
extra:
routes:
gitlab-mr:
events: ["merge_request"]
secret: "your-gitlab-secret-token"
prompt: |
Review this merge request:
Project: {project.path_with_namespace}
MR !{object_attributes.iid}: {object_attributes.title}
Author: {object_attributes.last_commit.author.name}
URL: {object_attributes.url}
Action: {object_attributes.action}
deliver: "log"
---
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-secret"
routes:
antenna-matches:
secret: "antenna-webhook-secret"
deliver: "telegram"
deliver_only: true
prompt: "🎉 New match: {match.user_name} matched with you!"
deliver_extra:
chat_id: "{match.telegram_chat_id}"
---
hermes webhook subscribe antenna-matches \
--deliver telegram \
--deliver-chat-id "123456789" \
--deliver-only \
--prompt "🎉 New match: {match.user_name} matched with you!" \
--description "Antenna match notifications"
---
hermes webhook subscribe github-issues \
--events "issues" \
--prompt "New issue #{issue.number}: {issue.title}\nBy: {issue.user.login}\n\n{issue.body}" \
--deliver telegram \
--deliver-chat-id "-100123456789" \
--description "Triage new GitHub issues"
---
hermes webhook list
---
hermes webhook remove github-issues
---
hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'
---
platforms:
webhook:
extra:
rate_limit: 60 # requests per minute
---
platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 MB
---
hermes gateway setup
---
hermes gateway setup
---
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
---
hermes gateway
---
WECOM_DM_POLICY=allowlist
---
WECOM_GROUP_POLICY=allowlist
---
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"
---
WECOM_CALLBACK_CORP_ID=your-corp-id
WECOM_CALLBACK_CORP_SECRET=your-corp-secret
WECOM_CALLBACK_AGENT_ID=1000002
WECOM_CALLBACK_TOKEN=your-callback-token
WECOM_CALLBACK_ENCODING_AES_KEY=your-43-char-aes-key
# Optional
WECOM_CALLBACK_HOST=0.0.0.0
WECOM_CALLBACK_PORT=8645
WECOM_CALLBACK_ALLOWED_USERS=user1,user2
---
hermes gateway start
---
platforms:
wecom_callback:
enabled: true
extra:
host: "0.0.0.0"
port: 8645
apps:
- name: "dept-a"
corp_id: "ww_corp_a"
corp_secret: "secret-a"
agent_id: "1000002"
token: "token-a"
encoding_aes_key: "key-a-43-chars..."
- name: "dept-b"
corp_id: "ww_corp_b"
corp_secret: "secret-b"
agent_id: "1000003"
token: "token-b"
encoding_aes_key: "key-b-43-chars..."
---
# อนุญาตเฉพาะผู้ใช้ที่ระบุ
WECOM_CALLBACK_ALLOWED_USERS=zhangsan,lisi,wangwu
# หรืออนุญาตผู้ใช้ทั้งหมด
WECOM_CALLBACK_ALLOW_ALL_USERS=true
---
pip install aiohttp cryptography
# Optional: for terminal QR code display
pip install hermes-agent[messaging]
---
hermes gateway setup
---
微信连接成功,account_id=your-account-id
---
WEIXIN_ACCOUNT_ID=your-account-id
# Optional: override the token (normally auto-saved from QR login)
# WEIXIN_TOKEN=your-bot-token
# Optional: restrict access
WEIXIN_DM_POLICY=open
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2
# Optional: restore legacy multiline splitting behavior
# WEIXIN_SPLIT_MULTILINE_MESSAGES=true
# Optional: home channel for cron/notifications
WEIXIN_HOME_CHANNEL=chat_id
WEIXIN_HOME_CHANNEL_NAME=Home
---
hermes gateway
---
WEIXIN_DM_POLICY=allowlist
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2
---
WEIXIN_GROUP_POLICY=allowlist
WEIXIN_GROUP_ALLOWED_USERS=group_id_1,group_id_2
---
hermes whatsapp
---
# Required
WHATSAPP_ENABLED=true
WHATSAPP_MODE=bot # "bot" หรือ "self-chat"
# การควบคุมการเข้าถึง - เลือกตัวเลือกใดตัวเลือกหนึ่ง:
WHATSAPP_ALLOWED_USERS=15551234567 # หมายเลขโทรศัพท์ที่คั่นด้วยเครื่องหมายจุลภาค (พร้อมรหัสประเทศ, ห้ามมี +)
# WHATSAPP_ALLOWED_USERS=* # หรือใช้ * เพื่ออนุญาตทุกคน
# WHATSAPP_ALLOW_ALL_USERS=true # หรือตั้งค่า flag นี้แทน (ผลลัพธ์เหมือนกับ *)
---
unauthorized_dm_behavior: pair
whatsapp:
unauthorized_dm_behavior: ignore
---
hermes gateway # Foreground
hermes gateway install # ติดตั้งเป็น user service
sudo hermes gateway install --system # สำหรับ Linux เท่านั้น: system service ที่บูตเครื่อง
---
hermes whatsapp
---
# ~/.hermes/config.yaml
whatsapp:
reply_prefix: "" # ข้อความว่างเปล่าจะปิด header
# reply_prefix: "🤖 *My Bot*\n──────\n" # Custom prefix (รองรับ \n สำหรับการขึ้นบรรทัดใหม่)
---
whatsapp:
unauthorized_dm_behavior: ignoreRAW_BUFFERClick to expand / collapse
📄 user-guide/messaging/webhooks.md
sidebar_position: 13 title: "Webhooks" description: "Receive events from GitHub, GitLab, and other services to trigger Hermes agent runs"
Webhooks
รับ event จากบริการภายนอก (เช่น GitHub, GitLab, JIRA, Stripe, เป็นต้น) และเรียกใช้ Hermes agent runs โดยอัตโนมัติ Webhook adapter ทำงานโดยการรัน HTTP server ที่รับ POST requests, ตรวจสอบ HMAC signatures, แปลง payloads ให้เป็น agent prompts, และส่งต่อ responses กลับไปยังแหล่งที่มาหรือไปยังแพลตฟอร์มอื่นที่กำหนดค่าไว้
agent จะประมวลผล event และสามารถตอบกลับได้โดยการโพสต์ comment บน PRs, ส่งข้อความไปยัง Telegram/Discord, หรือบันทึกผลลัพธ์
Quick Start
- เปิดใช้งานผ่าน
hermes gateway setupหรือ environment variables - กำหนด routes ใน
config.yamlหรือ สร้างแบบไดนามิกด้วยhermes webhook subscribe - ชี้บริการของคุณไปยัง
http://your-server:8644/webhooks/<route-name>
Setup
มีสองวิธีในการเปิดใช้งาน webhook adapter
ผ่าน setup wizard
hermes gateway setupทำตามคำแนะนำเพื่อเปิดใช้งาน webhooks, กำหนด port, และกำหนด global HMAC secret
ผ่าน environment variables
เพิ่มใน ~/.hermes/.env:
WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644 # default
WEBHOOK_SECRET=your-global-secretตรวจสอบ server
เมื่อ gateway ทำงานแล้ว:
curl http://localhost:8644/healthExpected response:
{"status": "ok", "platform": "webhook"}Configuring Routes {#configuring-routes}
Routes กำหนดวิธีการจัดการ webhook sources ที่แตกต่างกัน แต่ละ route คือ entry ที่มีชื่อภายใต้ platforms.webhook.extra.routes ในไฟล์ config.yaml ของคุณ
Route properties
| Property | Required | Description |
|---|---|---|
events | No | รายการประเภท event ที่ต้องการรับ (เช่น ["pull_request"]) หากว่างเปล่า จะรับทุก event type event type จะถูกอ่านจาก X-GitHub-Event, X-GitLab-Event, หรือ event_type ใน payload |
secret | Yes | HMAC secret สำหรับการตรวจสอบ signature จะใช้ global secret เป็นค่า fallback หากไม่ได้กำหนดบน route นั้นๆ กำหนดเป็น "INSECURE_NO_AUTH" สำหรับการทดสอบเท่านั้น (ข้ามการตรวจสอบ) |
prompt | No | Template string ที่สามารถเข้าถึง payload ด้วย dot-notation (เช่น {pull_request.title}) หากละเว้น จะ dump full JSON payload เข้าไปใน prompt |
skills | No | รายการชื่อ skill ที่จะโหลดสำหรับการรัน agent |
deliver | No | ที่ที่จะส่ง response: github_comment, telegram, discord, slack, signal, sms, whatsapp, matrix, mattermost, homeassistant, email, dingtalk, feishu, wecom, weixin, bluebubbles, qqbot, หรือ log (default) |
deliver_extra | No | การตั้งค่าการส่งมอบเพิ่มเติม - keys ขึ้นอยู่กับ deliver type (เช่น repo, pr_number, chat_id) ค่าต่างๆ รองรับ template แบบ {dot.notation} เช่นเดียวกับ prompt |
deliver_only | No | หากเป็น true จะข้าม agent ไปโดยสิ้นเชิง - template prompt ที่ถูก render จะกลายเป็นข้อความ literal ที่ถูกส่งออกไป ประหยัดค่า LLM tokens และส่งมอบได้ในระดับ sub-second ดู Direct Delivery Mode สำหรับ use cases |
Full example
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-fallback-secret"
routes:
github-pr:
events: ["pull_request"]
secret: "github-webhook-secret"
prompt: |
Review this pull request:
Repository: {repository.full_name}
PR #{number}: {pull_request.title}
Author: {pull_request.user.login}
URL: {pull_request.html_url}
Diff URL: {pull_request.diff_url}
Action: {action}
skills: ["github-code-review"]
deliver: "github_comment"
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
deploy-notify:
events: ["push"]
secret: "deploy-secret"
prompt: "New push to {repository.full_name} branch {ref}: {head_commit.message}"
deliver: "telegram"Prompt Templates
Prompts ใช้ dot-notation เพื่อเข้าถึง fields ซ้อนกันใน webhook payload:
{pull_request.title}resolve เป็นpayload["pull_request"]["title"]{repository.full_name}resolve เป็นpayload["repository"]["full_name"]{__raw__}- token พิเศษที่ dump entire payload ทั้งหมดเป็น JSON แบบ indented (ถูกตัดที่ 4000 characters) มีประโยชน์สำหรับการแจ้งเตือนแบบ monitoring หรือ webhooks ทั่วไปที่ agent ต้องการ full context- Keys ที่ขาดหายไปจะถูกทิ้งไว้เป็น string literal
{key}(ไม่มี error) - Nested dicts และ lists จะถูก JSON-serialized และถูกตัดที่ 2000 characters
คุณสามารถผสม {__raw__} เข้ากับตัวแปร template ทั่วไปได้:
prompt: "PR #{pull_request.number} by {pull_request.user.login}: {__raw__}"หากไม่มีการกำหนด prompt template สำหรับ route ใดๆ payload ทั้งหมดจะถูก dump เป็น JSON แบบ indented (ถูกตัดที่ 4000 characters)
template แบบ dot-notation เดียวกันสามารถใช้ได้ในค่า deliver_extra
Forum Topic Delivery
เมื่อส่ง webhook responses ไปยัง Telegram คุณสามารถกำหนดเป้าหมายไปยัง forum topic เฉพาะได้โดยการรวม message_thread_id (หรือ thread_id) ใน deliver_extra:
webhooks:
routes:
alerts:
events: ["alert"]
prompt: "Alert: {__raw__}"
deliver: "telegram"
deliver_extra:
chat_id: "-1001234567890"
message_thread_id: "42"หากไม่ได้ให้ chat_id ใน deliver_extra การส่งมอบจะ fallback ไปยัง home channel ที่กำหนดค่าไว้สำหรับ target platform
GitHub PR Review (Step by Step) {#github-pr-review}
คู่มือนี้ตั้งค่าการตรวจสอบโค้ดอัตโนมัติสำหรับทุก pull request
1. สร้าง webhook ใน GitHub
- ไปที่ repository ของคุณ -> Settings -> Webhooks -> Add webhook
- ตั้งค่า Payload URL เป็น
http://your-server:8644/webhooks/github-pr - ตั้งค่า Content type เป็น
application/json - ตั้งค่า Secret ให้ตรงกับ route config ของคุณ (เช่น
github-webhook-secret) - ภายใต้ Which events?, เลือก Let me select individual events และเลือก Pull requests
- คลิก Add webhook
2. เพิ่ม route config
เพิ่ม route github-pr ในไฟล์ ~/.hermes/config.yaml ของคุณตามตัวอย่างข้างต้น
3. ตรวจสอบว่า gh CLI ได้รับการ authenticate
delivery type github_comment ใช้ GitHub CLI ในการโพสต์ comment:
gh auth login4. ทดสอบ
เปิด pull request บน repository webhook จะทำงาน, Hermes จะประมวลผล event, และโพสต์ review comment บน PR
GitLab Webhook Setup {#gitlab-webhook-setup}
GitLab webhooks ทำงานคล้ายกัน แต่ใช้กลไกการตรวจสอบสิทธิ์ที่แตกต่างกัน GitLab จะส่ง secret เป็น header X-Gitlab-Token แบบ plain (ต้องตรงกับ string เป๊ะๆ ไม่ใช่ HMAC)
1. สร้าง webhook ใน GitLab
- ไปที่ project ของคุณ -> Settings -> Webhooks
- ตั้งค่า URL เป็น
http://your-server:8644/webhooks/gitlab-mr - ป้อน Secret token ของคุณ
- เลือก Merge request events (และ event อื่นๆ ที่คุณต้องการ)
- คลิก Add webhook
2. เพิ่ม route config
platforms:
webhook:
enabled: true
extra:
routes:
gitlab-mr:
events: ["merge_request"]
secret: "your-gitlab-secret-token"
prompt: |
Review this merge request:
Project: {project.path_with_namespace}
MR !{object_attributes.iid}: {object_attributes.title}
Author: {object_attributes.last_commit.author.name}
URL: {object_attributes.url}
Action: {object_attributes.action}
deliver: "log"Delivery Options {#delivery-options}
field deliver ควบคุมว่า response ของ agent จะไปที่ใดหลังจากประมวลผล webhook event
| Deliver Type | Description |
|---|---|
log | บันทึก response ไปยัง gateway log output นี่คือค่า default และมีประโยชน์สำหรับการทดสอบ |
github_comment | โพสต์ response เป็น PR/issue comment ผ่าน gh CLI ต้องใช้ deliver_extra.repo และ deliver_extra.pr_number ต้องติดตั้งและ authenticate gh CLI บน gateway host (gh auth login) |
telegram | ส่ง response ไปยัง Telegram ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
discord | ส่ง response ไปยัง Discord ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
slack | ส่ง response ไปยัง Slack ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
signal | ส่ง response ไปยัง Signal ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
sms | ส่ง response ไปยัง SMS ผ่าน Twilio ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
whatsapp | ส่ง response ไปยัง WhatsApp ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
matrix | ส่ง response ไปยัง Matrix ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
mattermost | ส่ง response ไปยัง Mattermost ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
homeassistant | ส่ง response ไปยัง Home Assistant ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
email | ส่ง response ไปยัง Email ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
dingtalk | ส่ง response ไปยัง DingTalk ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
feishu | ส่ง response ไปยัง Feishu/Lark ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
wecom | ส่ง response ไปยัง WeCom ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
weixin | ส่ง response ไปยัง Weixin (WeChat) ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
bluebubbles | ส่ง response ไปยัง BlueBubbles (iMessage) ใช้ home channel หรือระบุ chat_id ใน deliver_extra |
สำหรับการส่งมอบข้ามแพลตฟอร์ม target platform ต้องถูกเปิดใช้งานและเชื่อมต่อใน gateway หากไม่ได้ให้ chat_id ใน deliver_extra response จะถูกส่งไปยัง home channel ที่กำหนดค่าไว้สำหรับแพลตฟอร์มนั้นๆ
Direct Delivery Mode {#direct-delivery-mode}
โดยค่าเริ่มต้น ทุก POST webhook จะเรียกใช้ agent run - payload จะกลายเป็น prompt, agent จะประมวลผล, และ response ของ agent จะถูกส่งมอบ สิ่งนี้มีค่าใช้จ่าย LLM tokens ในทุก event
สำหรับ use cases ที่คุณต้องการเพียงแค่ push notification ธรรมดา - ไม่มี reasoning, ไม่มี agent loop, เพียงแค่ส่งมอบข้อความ - ให้ตั้งค่า deliver_only: true บน route template template prompt ที่ถูก render จะกลายเป็น message body literal และ adapter จะส่งมันโดยตรงไปยัง delivery target ที่กำหนดค่าไว้
When to use direct delivery
- External service push - Supabase/Firebase webhook ทำงานเมื่อมีการเปลี่ยนแปลงฐานข้อมูล -> แจ้งเตือนผู้ใช้ใน Telegram ทันที
- Monitoring alerts - Datadog/Grafana alert webhook -> push ไปยังช่อง Discord
- Inter-agent pings - Agent A แจ้งเตือนผู้ใช้ของ Agent B ว่างานที่รันนานเสร็จแล้ว
- Background job completion - Cron job เสร็จสิ้น -> โพสต์ผลลัพธ์ไปยัง Slack
Benefits:
- Zero LLM tokens - agent จะไม่ถูกเรียกใช้เลย
- Sub-second delivery - การเรียก adapter ครั้งเดียว, ไม่มี reasoning loop
- Same security as agent mode - HMAC auth, rate limits, idempotency, และ body-size limits ยังคงใช้ได้ทั้งหมด
- Synchronous response - POST จะคืนค่า
200 OKเมื่อการส่งมอบสำเร็จ หรือ502หาก target ปฏิเสธ เพื่อให้บริการต้นทางของคุณสามารถ retry ได้อย่างชาญฉลาด
Example: Telegram push from Supabase
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-secret"
routes:
antenna-matches:
secret: "antenna-webhook-secret"
deliver: "telegram"
deliver_only: true
prompt: "🎉 New match: {match.user_name} matched with you!"
deliver_extra:
chat_id: "{match.telegram_chat_id}"Supabase edge function จะ sign payload ด้วย HMAC-SHA256 และ POST ไปที่ https://your-server:8644/webhooks/antenna-matches webhook adapter จะตรวจสอบ signature, render template จาก payload, ส่งมอบไปยัง Telegram, และคืนค่า 200 OK
Example: Dynamic subscription via CLI
hermes webhook subscribe antenna-matches \
--deliver telegram \
--deliver-chat-id "123456789" \
--deliver-only \
--prompt "🎉 New match: {match.user_name} matched with you!" \
--description "Antenna match notifications"Response codes
| Status | Meaning |
|---|---|
200 OK | ส่งมอบสำเร็จ Body: {"status": "delivered", "route": "...", "target": "...", "delivery_id": "..."} |
200 OK (status=duplicate) | Duplicate X-GitHub-Delivery ID ภายในช่วงเวลา idempotency TTL (1 ชั่วโมง) ไม่มีการส่งมอบซ้ำ |
401 Unauthorized | HMAC signature ไม่ถูกต้องหรือขาดหายไป |
400 Bad Request | JSON body รูปแบบไม่ถูกต้อง |
404 Not Found | ชื่อ route ไม่รู้จัก |
413 Payload Too Large | Body เกิน max_body_bytes |
429 Too Many Requests | เกิน rate limit ของ route |
502 Bad Gateway | Target adapter ปฏิเสธข้อความหรือเกิดข้อผิดพลาด ข้อผิดพลาดจะถูกบันทึกที่ฝั่ง server; response body จะเป็น Delivery failed ทั่วไปเพื่อหลีกเลี่ยงการเปิดเผย internal adapter details |
Configuration gotchas
deliver_only: trueต้องใช้deliverเป็น target จริงdeliver: log(หรือละเว้นdeliver) จะถูกปฏิเสธเมื่อเริ่มต้น - adapter จะปฏิเสธที่จะเริ่มทำงานหากพบ route ที่กำหนดค่าผิดพลาด- field
skillsจะถูกละเลยใน direct delivery mode (ไม่มีการรัน agent, ดังนั้นจึงไม่มีอะไรให้ inject skills) - การ render template ใช้ syntax
{dot.notation}เดียวกันกับ agent mode รวมถึง token{__raw__} - Idempotency ใช้ header
X-GitHub-Delivery/X-Request-IDเดียวกัน - การ retry ด้วย ID เดียวกันจะคืนค่าstatus=duplicateและจะไม่ส่งมอบซ้ำ
Dynamic Subscriptions (CLI) {#dynamic-subscriptions}
นอกจาก routes แบบ static ใน config.yaml แล้ว คุณยังสามารถสร้าง webhook subscriptions แบบไดนามิกโดยใช้คำสั่ง CLI hermes webhook นี้มีประโยชน์อย่างยิ่งเมื่อ agent เองจำเป็นต้องตั้งค่า triggers แบบ event-driven
Create a subscription
hermes webhook subscribe github-issues \
--events "issues" \
--prompt "New issue #{issue.number}: {issue.title}\nBy: {issue.user.login}\n\n{issue.body}" \
--deliver telegram \
--deliver-chat-id "-100123456789" \
--description "Triage new GitHub issues"สิ่งนี้จะคืนค่า webhook URL และ HMAC secret ที่สร้างขึ้นโดยอัตโนมัติ กำหนดค่าบริการของคุณให้ POST ไปยัง URL นั้น
List subscriptions
hermes webhook listRemove a subscription
hermes webhook remove github-issuesTest a subscription
hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'How dynamic subscriptions work
- Subscriptions ถูกจัดเก็บใน
~/.hermes/webhook_subscriptions.json - webhook adapter จะ hot-reload ไฟล์นี้เมื่อมี request เข้ามาแต่ละครั้ง (mtime-gated, overhead น้อยมาก)
- Static routes จาก
config.yamlจะมีลำดับความสำคัญเหนือกว่า dynamic routes ที่มีชื่อเดียวกันเสมอ - Dynamic subscriptions ใช้รูปแบบและขีดความสามารถเดียวกับ static routes (events, prompt templates, skills, delivery)
- ไม่จำเป็นต้อง restart gateway - subscribe และพร้อมใช้งานทันที
Agent-driven subscriptions
agent สามารถสร้าง subscriptions ผ่าน terminal tool เมื่อได้รับคำแนะนำจาก webhook-subscriptions skill ให้ขอ agent ว่า "set up a webhook for GitHub issues" และมันจะรันคำสั่ง hermes webhook subscribe ที่เหมาะสม
Security {#security}
webhook adapter มีหลายชั้นของความปลอดภัย:
HMAC signature validation
adapter ตรวจสอบ webhook signatures ที่เข้ามาโดยใช้ method ที่เหมาะสมสำหรับแต่ละ source:
- GitHub: header
X-Hub-Signature-256- HMAC-SHA256 hex digest ที่ขึ้นต้นด้วยsha256= - GitLab: header
X-Gitlab-Token- plain secret string match - Generic: header
X-Webhook-Signature- raw HMAC-SHA256 hex digest
หากมีการกำหนด secret แต่ไม่มี header signature ที่รู้จัก ระบบจะปฏิเสธ request
Secret is required
ทุก route ต้องมี secret - ไม่ว่าจะกำหนดโดยตรงบน route หรือสืบทอดมาจาก global secret Routes ที่ไม่มี secret จะทำให้ adapter ล้มเหลวเมื่อเริ่มต้นทำงาน สำหรับการพัฒนา/ทดสอบเท่านั้น คุณสามารถตั้งค่า secret เป็น "INSECURE_NO_AUTH" เพื่อข้ามการตรวจสอบทั้งหมด
Rate limiting
แต่ละ route ถูกจำกัด rate limit ที่ 30 requests per minute โดยค่า default (fixed-window) กำหนดค่านี้ทั่วโลก:
platforms:
webhook:
extra:
rate_limit: 60 # requests per minuteRequests ที่เกิน limit จะได้รับ response 429 Too Many Requests
Idempotency
Delivery IDs (จาก X-GitHub-Delivery, X-Request-ID, หรือ timestamp fallback) จะถูกแคชเป็นเวลา 1 hour การส่งมอบซ้ำ (เช่น webhook retries) จะถูกข้ามอย่างเงียบๆ ด้วย response 200 ป้องกันการรัน agent ซ้ำ
Body size limits
Payloads ที่เกิน 1 MB จะถูกปฏิเสธก่อนที่จะอ่าน body กำหนดค่านี้:
platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 MBPrompt injection risk
:::warning Webhook payloads มีข้อมูลที่ควบคุมโดยผู้โจมตี - PR titles, commit messages, issue descriptions, ฯลฯ อาจมีคำสั่งที่เป็นอันตรายได้ทั้งหมด ควรรัน gateway ในสภาพแวดล้อมที่ถูกจำกัด (Docker, VM) เมื่อเปิดเผยต่ออินเทอร์เน็ต พิจารณาใช้ Docker หรือ SSH terminal backend เพื่อการแยกส่วน :::
Troubleshooting {#troubleshooting}
Webhook not arriving
- ตรวจสอบว่า port ถูกเปิดและเข้าถึงได้จาก webhook source
- ตรวจสอบ firewall rules - port
8644(หรือ port ที่กำหนดค่า) ต้องเปิดอยู่ - ตรวจสอบว่า URL path ตรงกัน:
http://your-server:8644/webhooks/<route-name> - ใช้ endpoint
/healthเพื่อยืนยันว่า server กำลังทำงาน
Signature validation failing
- ตรวจสอบให้แน่ใจว่า secret ใน route config ตรงกับ secret ที่กำหนดค่าใน webhook source อย่างแน่นอน
- สำหรับ GitHub, secret เป็นแบบ HMAC - ตรวจสอบ
X-Hub-Signature-256 - สำหรับ GitLab, secret เป็นแบบ plain token match - ตรวจสอบ
X-Gitlab-Token - ตรวจสอบ gateway logs สำหรับคำเตือน
Invalid signature
Event being ignored
- ตรวจสอบว่า event type อยู่ในรายการ
eventsของ route คุณ - GitHub events ใช้ค่าเช่น
pull_request,push,issues(ค่า headerX-GitHub-Event) - GitLab events ใช้ค่าเช่น
merge_request,push(ค่า headerX-Gitlab-Event) - หาก
eventsว่างเปล่าหรือไม่ถูกตั้งค่า จะรับทุก event
Agent not responding
- รัน gateway ใน foreground เพื่อดู logs:
hermes gateway run - ตรวจสอบว่า prompt template render อย่างถูกต้อง
- ตรวจสอบว่า delivery target ถูกกำหนดค่าและเชื่อมต่อแล้ว
Duplicate responses
- Idempotency cache ควรป้องกันสิ่งนี้ - ตรวจสอบว่า webhook source ส่ง delivery ID header (
X-GitHub-DeliveryหรือX-Request-ID) - Delivery IDs ถูกแคชเป็นเวลา 1 hour
gh CLI errors (GitHub comment delivery)
- รัน
gh auth loginบน gateway host - ตรวจสอบว่า GitHub user ที่ authenticate มี write access ถึง repository
- ตรวจสอบว่า
ghถูกติดตั้งและอยู่ใน PATH
Environment Variables {#environment-variables}
| Variable | Description | Default |
|---|---|---|
WEBHOOK_ENABLED | เปิดใช้งาน webhook platform adapter | false |
WEBHOOK_PORT | HTTP server port สำหรับรับ webhooks | 8644 |
WEBHOOK_SECRET | Global HMAC secret (ใช้เป็น fallback เมื่อ route ไม่ได้ระบุของตัวเอง) | (none) |
📄 user-guide/messaging/wecom.md
sidebar_position: 14 title: "WeCom (Enterprise WeChat)" description: "Connect Hermes Agent to WeCom via the AI Bot WebSocket gateway"
WeCom (Enterprise WeChat)
เชื่อมต่อ Hermes เข้ากับ WeCom (企业微信) ซึ่งเป็นแพลตฟอร์มการสื่อสารองค์กรของ Tencent อะแดปเตอร์นี้ใช้ WeCom's AI Bot WebSocket gateway สำหรับการสื่อสารแบบสองทิศทางแบบเรียลไทม์ ไม่จำเป็นต้องมี public endpoint หรือ webhook ใดๆ
Prerequisites
- บัญชีองค์กร WeCom
- AI Bot ที่สร้างขึ้นใน WeCom Admin Console
- Bot ID และ Secret จากหน้าข้อมูลประจำตัวของบอท
- Python packages:
aiohttpและhttpx
Setup
Step 1: Create an AI Bot
Recommended: Scan-to-Create (one command)
hermes gateway setupเลือก WeCom และสแกน QR code ด้วยแอป WeCom บนมือถือของคุณ Hermes จะสร้างแอปพลิเคชันบอทโดยอัตโนมัติพร้อมสิทธิ์ที่ถูกต้องและบันทึก credentials ให้
Setup wizard จะ:
- แสดง QR code ใน terminal ของคุณ
- รอให้คุณสแกนด้วยแอป WeCom บนมือถือ
- ดึง Bot ID และ Secret โดยอัตโนมัติ
- แนะนำคุณตลอดการตั้งค่า access control
Alternative: Manual Setup
หากไม่สามารถใช้ scan-to-create ได้ wizard จะกลับไปใช้วิธีป้อนข้อมูลด้วยตนเอง:
- เข้าสู่ระบบ WeCom Admin Console
- ไปที่ Applications → Create Application → AI Bot
- กำหนดชื่อและคำอธิบายของบอท
- คัดลอก Bot ID และ Secret จากหน้า credentials
- รัน
hermes gateway setup, เลือก WeCom, และป้อน credentials เมื่อระบบแจ้ง
:::warning เก็บ Bot Secret เป็นความลับ ใครก็ตามที่มีสิ่งนี้สามารถปลอมตัวเป็นบอทของคุณได้ :::
Step 2: Configure Hermes
Option A: Interactive Setup (Recommended)
hermes gateway setupเลือก WeCom และทำตามคำแนะนำ wizard จะแนะนำคุณตลอดการตั้งค่า:
- Bot credentials (ผ่านการสแกน QR หรือการป้อนข้อมูลด้วยตนเอง)
- Access control settings (allowlist, pairing mode, หรือ open access)
- 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_idStep 3: Start the gateway
hermes gatewayFeatures
- WebSocket transport - การเชื่อมต่อแบบ persistent ไม่จำเป็นต้องมี public endpoint
- DM and group messaging - นโยบายการเข้าถึงที่กำหนดค่าได้
- Per-group sender allowlists - การควบคุมระดับละเอียดว่าใครสามารถโต้ตอบในแต่ละกลุ่มได้
- Media support - การอัปโหลดและดาวน์โหลดรูปภาพ ไฟล์ เสียง และวิดีโอ
- AES-encrypted media - การถอดรหัสอัตโนมัติสำหรับไฟล์แนบขาเข้า
- Quote context - รักษาการสนทนาแบบ thread เมื่อมีการตอบกลับ
- Markdown rendering - การตอบกลับแบบ rich text
- Reply-mode streaming - เชื่อมโยงการตอบกลับกับบริบทข้อความขาเข้า
- Auto-reconnect - การหน่วงเวลาแบบ exponential backoff เมื่อการเชื่อมต่อหลุด
Configuration Options
กำหนดค่าเหล่านี้ใน config.yaml ภายใต้ platforms.wecom.extra:
| Key | Default | Description |
|---|---|---|
bot_id | — | WeCom AI Bot ID (required) |
secret | — | WeCom AI Bot Secret (required) |
websocket_url | wss://openws.work.weixin.qq.com | URL ของ WebSocket gateway |
dm_policy | open | การเข้าถึง DM: open, allowlist, disabled, pairing |
group_policy | open | การเข้าถึงกลุ่ม: open, allowlist, disabled |
allow_from | [] | User IDs ที่ได้รับอนุญาตสำหรับ DM (เมื่อ dm_policy=allowlist) |
group_allow_from | [] | Group IDs ที่ได้รับอนุญาต (เมื่อ group_policy=allowlist) |
groups | {} | การกำหนดค่าต่อกลุ่ม (ดูด้านล่าง) |
Access Policies
DM Policy
ควบคุมว่าใครสามารถส่งข้อความส่วนตัว (DM) ถึงบอทได้:
| Value | Behavior |
|---|---|
open | ทุกคนสามารถ DM บอทได้ (ค่าเริ่มต้น) |
allowlist | เฉพาะ user IDs ใน allow_from เท่านั้นที่สามารถ DM ได้ |
disabled | เพิกเฉยต่อ DM ทั้งหมด |
pairing | โหมดจับคู่ (สำหรับการตั้งค่าเริ่มต้น) |
WECOM_DM_POLICY=allowlistGroup Policy
ควบคุมว่าบอทจะตอบกลับในกลุ่มใด:
| Value | Behavior |
|---|---|
open | บอทตอบกลับในทุกกลุ่ม (ค่าเริ่มต้น) |
allowlist | บอทจะตอบกลับเฉพาะ group IDs ที่ระบุใน group_allow_from |
disabled | เพิกเฉยต่อข้อความกลุ่มทั้งหมด |
WECOM_GROUP_POLICY=allowlistPer-Group Sender Allowlists
สำหรับการควบคุมระดับละเอียด คุณสามารถจำกัดผู้ใช้ที่ได้รับอนุญาตให้โต้ตอบกับบอทภายในกลุ่มเฉพาะได้ สิ่งนี้กำหนดค่าใน 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"How it works:
group_policyและgroup_allow_fromควบคุมว่ากลุ่มนั้นได้รับอนุญาตหรือไม่- หากกลุ่มผ่านการตรวจสอบระดับบนสุดแล้ว รายการ
groups.<group_id>.allow_from(ถ้ามี) จะจำกัดผู้ส่งภายในกลุ่มนั้นๆ ที่สามารถโต้ตอบกับบอทได้เพิ่มเติม - การระบุกลุ่มแบบ wildcard
"*"ทำหน้าที่เป็นค่าเริ่มต้นสำหรับกลุ่มที่ไม่ได้ระบุอย่างชัดเจน - รายการ allowlist รองรับ wildcard
*เพื่ออนุญาตผู้ใช้ทั้งหมด และรายการเหล่านี้ไม่คำนึงถึงตัวพิมพ์เล็ก-ใหญ่ (case-insensitive) - รายการสามารถใช้ prefix รูปแบบ
wecom:user:หรือwecom:group:ได้ตามความสมัครใจ - prefix จะถูกลบออกโดยอัตโนมัติ
หากไม่มีการกำหนด allow_from สำหรับกลุ่ม ผู้ใช้ทุกคนในกลุ่มนั้นจะได้รับอนุญาต (โดยสมมติว่าตัวกลุ่มเองผ่านการตรวจสอบนโยบายระดับบนสุดแล้ว)
Media Support
Inbound (receiving)
อะแดปเตอร์จะรับไฟล์แนบสื่อจากผู้ใช้และแคชไว้ในเครื่องสำหรับการประมวลผลของ agent:
| Type | How it's handled |
|---|---|
| Images | ดาวน์โหลดและแคชในเครื่อง รองรับทั้งรูปภาพที่อ้างอิงจาก URL และรูปภาพที่เข้ารหัส base64 |
| Files | ดาวน์โหลดและแคช ชื่อไฟล์จะถูกเก็บรักษาจากข้อความต้นฉบับ |
| Voice | จะมีการดึงข้อความถอดเสียงจากข้อความเสียงหากมีให้ |
| Mixed messages | ข้อความประเภทผสมของ WeCom (ข้อความ + รูปภาพ) จะถูกแยกวิเคราะห์และดึงส่วนประกอบทั้งหมดออกมา |
Quoted messages: สื่อจากข้อความที่ถูกอ้างถึง (replied-to) จะถูกดึงออกมาด้วย ทำให้ agent มีบริบทว่าผู้ใช้กำลังตอบกลับอะไร
AES-Encrypted Media Decryption
WeCom จะเข้ารหัสไฟล์แนบสื่อขาเข้าบางส่วนด้วย AES-256-CBC อะแดปเตอร์จะจัดการสิ่งนี้โดยอัตโนมัติ:
- เมื่อรายการสื่อขาเข้ามี field
aeskeyอะแดปเตอร์จะดาวน์โหลดไบต์ที่เข้ารหัสและถอดรหัสด้วย AES-256-CBC พร้อม PKCS#7 padding - AES key คือค่าที่ถอดรหัส base64 ของ field
aeskey(ต้องมีขนาด 32 ไบต์พอดี) - IV จะถูกดึงมาจาก 16 ไบต์แรกของ key
- สิ่งนี้ต้องใช้ Python package
cryptography(pip install cryptography)
ไม่จำเป็นต้องมีการกำหนดค่า - การถอดรหัสจะเกิดขึ้นอย่างโปร่งใสเมื่อได้รับสื่อที่เข้ารหัส
Outbound (sending)
| Method | What it sends | Size limit |
|---|---|---|
send | ข้อความข้อความ Markdown | 4000 chars |
send_image / send_image_file | ข้อความรูปภาพแบบ Native | 10 MB |
send_document | ไฟล์แนบ | 20 MB |
send_voice | ข้อความเสียง (รองรับเฉพาะรูปแบบ AMR สำหรับเสียง Native) | 2 MB |
send_video | ข้อความวิดีโอ | 10 MB |
Chunked upload: ไฟล์จะถูกอัปโหลดเป็น chunks ขนาด 512 KB ผ่านโปรโตคอลสามขั้นตอน (init -> chunks -> finish) อะแดปเตอร์จัดการสิ่งนี้โดยอัตโนมัติ
Automatic downgrade: เมื่อสื่อมีขนาดเกินขีดจำกัดของประเภท Native แต่ยังอยู่ในขีดจำกัดไฟล์ 20 MB โดยรวม จะถูกส่งเป็นไฟล์แนบทั่วไปแทนโดยอัตโนมัติ:
- Images > 10 MB → ส่งเป็นไฟล์
- Videos > 10 MB → ส่งเป็นไฟล์
- Voice > 2 MB → ส่งเป็นไฟล์
- Non-AMR audio → ส่งเป็นไฟล์ (WeCom รองรับเฉพาะ AMR สำหรับเสียง Native)
ไฟล์ที่เกินขีดจำกัด 20 MB โดยรวมจะถูกปฏิเสธพร้อมข้อความแจ้งข้อมูลที่ส่งไปยังแชท
Reply-Mode Stream Responses
เมื่อบอทได้รับข้อความผ่าน WeCom callback อะแดปเตอร์จะจดจำ request ID ขาเข้า หากมีการส่งการตอบกลับในขณะที่บริบทของ request ยังทำงานอยู่ อะแดปเตอร์จะใช้ reply-mode ของ WeCom (aibot_respond_msg) พร้อม streaming เพื่อเชื่อมโยงการตอบกลับโดยตรงกับข้อความขาเข้า สิ่งนี้ให้ประสบการณ์การสนทนาที่เป็นธรรมชาติยิ่งขึ้นใน WeCom client
หากบริบทของ request ขาเข้าหมดอายุหรือไม่พร้อมใช้งาน อะแดปเตอร์จะย้อนกลับไปใช้การส่งข้อความเชิงรุกผ่าน aibot_send_msg
Reply-mode ยังใช้ได้กับสื่อ: สื่อที่อัปโหลดสามารถถูกส่งเป็น reply ไปยังข้อความต้นทางได้
Connection and Reconnection
อะแดปเตอร์จะรักษาการเชื่อมต่อ WebSocket แบบ persistent ไปยัง gateway ของ WeCom ที่ wss://openws.work.weixin.qq.com
Connection Lifecycle
- Connect: เปิดการเชื่อมต่อ WebSocket และส่ง frame การตรวจสอบสิทธิ์
aibot_subscribeพร้อม bot_id และ secret - Heartbeat: ส่ง frame ping ระดับแอปพลิเคชันทุก 30 วินาทีเพื่อรักษาการเชื่อมต่อให้มีชีวิตอยู่
- Listen: อ่าน frame ขาเข้าอย่างต่อเนื่องและกระจาย message callbacks
Reconnection Behavior
เมื่อการเชื่อมต่อหลุด อะแดปเตอร์จะใช้ exponential backoff เพื่อเชื่อมต่อใหม่:
| Attempt | Delay |
|---|---|
| 1st retry | 2 seconds |
| 2nd retry | 5 seconds |
| 3rd retry | 10 seconds |
| 4th retry | 30 seconds |
| 5th+ retry | 60 seconds |
หลังจากการเชื่อมต่อใหม่ที่สำเร็จแต่ละครั้ง ตัวนับ backoff จะรีเซ็ตเป็นศูนย์ Future ของ request ที่ค้างอยู่ทั้งหมดจะล้มเหลวเมื่อ disconnect เพื่อไม่ให้ caller ค้างไปเรื่อยๆ
Deduplication
ข้อความขาเข้าจะถูกทำ deduplication โดยใช้ message IDs ภายในหน้าต่าง 5 นาที และแคชสูงสุด 1000 รายการ สิ่งนี้ป้องกันการประมวลผลข้อความซ้ำซ้อนระหว่างการเชื่อมต่อใหม่หรือปัญหาเครือข่าย
All Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
WECOM_BOT_ID | ✅ | — | WeCom AI Bot ID |
WECOM_SECRET | ✅ | — | WeCom AI Bot Secret |
WECOM_ALLOWED_USERS | — | (empty) | User IDs ที่คั่นด้วยเครื่องหมายคอมม่าสำหรับ allowlist ระดับ gateway |
WECOM_HOME_CHANNEL | — | — | Chat ID สำหรับ output ของ cron/notification |
WECOM_WEBSOCKET_URL | — | wss://openws.work.weixin.qq.com | URL ของ WebSocket gateway |
WECOM_DM_POLICY | — | open | นโยบายการเข้าถึง DM |
WECOM_GROUP_POLICY | — | open | นโยบายการเข้าถึงกลุ่ม |
Troubleshooting
| Problem | Fix |
|---|---|
WECOM_BOT_ID and WECOM_SECRET are required | กำหนด env vars ทั้งคู่ หรือกำหนดค่าใน setup wizard |
WeCom startup failed: aiohttp not installed | ติดตั้ง aiohttp: pip install aiohttp |
WeCom startup failed: httpx not installed | ติดตั้ง httpx: pip install httpx |
invalid secret (errcode=40013) | ตรวจสอบว่า secret ตรงกับ credentials ของบอทหรือไม่ |
Timed out waiting for subscribe acknowledgement | ตรวจสอบการเชื่อมต่อเครือข่ายไปยัง openws.work.weixin.qq.com |
| Bot doesn't respond in groups | ตรวจสอบการตั้งค่า group_policy และตรวจสอบให้แน่ใจว่า group ID อยู่ใน group_allow_from |
| Bot ignores certain users in a group | ตรวจสอบรายการ allow_from ต่อกลุ่มในส่วน groups config section |
| Media decryption fails | ติดตั้ง cryptography: pip install cryptography |
cryptography is required for WeCom media decryption | สื่อขาเข้าถูกเข้ารหัส AES. ติดตั้ง: pip install cryptography |
| Voice messages sent as files | WeCom รองรับเฉพาะรูปแบบ AMR สำหรับเสียง Native. รูปแบบอื่นจะถูกลดระดับเป็นไฟล์โดยอัตโนมัติ |
File too large error | WeCom มีขีดจำกัดสูงสุด 20 MB สำหรับการอัปโหลดไฟล์ทั้งหมด. ให้บีบอัดหรือแบ่งไฟล์ |
| Images sent as files | รูปภาพ > 10 MB เกินขีดจำกัดรูปภาพ Native และถูกลดระดับเป็นไฟล์แนบโดยอัตโนมัติ |
Timeout sending message to WeCom | WebSocket อาจหลุด ตรวจสอบ logs สำหรับข้อความการเชื่อมต่อใหม่ |
WeCom websocket closed during authentication | ปัญหาเครือข่ายหรือ credentials ไม่ถูกต้อง. ตรวจสอบ bot_id และ secret |
📄 user-guide/messaging/wecom-callback.md
sidebar_position: 15
WeCom Callback (Self-Built App)
การเชื่อมต่อ Hermes เข้ากับ WeCom (Enterprise WeChat) ในรูปแบบแอปพลิเคชันที่สร้างเอง (self-built) สำหรับองค์กร โดยใช้โมเดล callback/webhook
:::info WeCom Bot vs WeCom Callback Hermes รองรับโหมดการเชื่อมต่อ WeCom สองโหมด:
- WeCom Bot - รูปแบบบอท (bot-style) เชื่อมต่อผ่าน WebSocket มีการตั้งค่าที่ง่ายกว่า และใช้งานได้ในกลุ่มแชท
- WeCom Callback (หน้านี้) - แอปพลิเคชันที่สร้างเอง (self-built app) รับ callback แบบ XML ที่เข้ารหัส จะแสดงเป็นแอปพลิเคชันหลักในแถบด้านข้างของ WeCom ของผู้ใช้ รองรับการกำหนดเส้นทาง (routing) ข้ามองค์กรหลายแห่ง :::
วิธีการทำงาน
- คุณต้องลงทะเบียนแอปพลิเคชันที่สร้างเองใน WeCom Admin Console
- WeCom จะส่งข้อมูล XML ที่เข้ารหัสไปยัง HTTP callback endpoint ของคุณ
- Hermes จะถอดรหัสข้อความและจัดคิวสำหรับ agent
- ตอบรับทันที (silent - ไม่แสดงอะไรแก่ผู้ใช้)
- agent จะดำเนินการตามคำขอ (โดยทั่วไปใช้เวลา 3-30 นาที)
- การตอบกลับจะถูกส่งออกไปเชิงรุก (proactively) ผ่าน WeCom
message/sendAPI
สิ่งที่ต้องเตรียม
- บัญชีองค์กร WeCom ที่มีสิทธิ์ผู้ดูแลระบบ (admin access)
- แพ็กเกจ Python
aiohttpและhttpx(รวมอยู่ในการติดตั้งเริ่มต้น) - เซิร์ฟเวอร์ที่สามารถเข้าถึงได้จากสาธารณะสำหรับ URL callback (หรือใช้ tunnel เช่น ngrok)
การตั้งค่า
1. สร้างแอปพลิเคชันที่สร้างเองใน WeCom
- ไปที่ WeCom Admin Console → Applications → Create App
- จด Corp ID ของคุณ (แสดงที่ส่วนบนของ admin console)
- ในการตั้งค่าแอป ให้สร้าง Corp Secret
- จด Agent ID จากหน้าภาพรวมของแอป
- ภายใต้ Receive Messages ให้กำหนดค่า callback URL:
- URL:
http://YOUR_PUBLIC_IP:8645/wecom/callback - Token: สร้าง token แบบสุ่ม (WeCom จะให้มา)
- EncodingAESKey: สร้าง key (WeCom จะให้มา)
- URL:
2. กำหนดค่า Environment Variables
เพิ่มในไฟล์ .env ของคุณ:
WECOM_CALLBACK_CORP_ID=your-corp-id
WECOM_CALLBACK_CORP_SECRET=your-corp-secret
WECOM_CALLBACK_AGENT_ID=1000002
WECOM_CALLBACK_TOKEN=your-callback-token
WECOM_CALLBACK_ENCODING_AES_KEY=your-43-char-aes-key
# Optional
WECOM_CALLBACK_HOST=0.0.0.0
WECOM_CALLBACK_PORT=8645
WECOM_CALLBACK_ALLOWED_USERS=user1,user23. เริ่มต้น Gateway
hermes gateway startcallback adapter จะเริ่ม HTTP server บนพอร์ตที่กำหนด WeCom จะตรวจสอบ callback URL ผ่าน GET request จากนั้นจึงเริ่มส่งข้อความผ่าน POST
Reference การกำหนดค่า
กำหนดค่าเหล่านี้ใน config.yaml ภายใต้ platforms.wecom_callback.extra หรือใช้ environment variables:
| Setting | Default | Description |
|---|---|---|
corp_id | - | WeCom enterprise Corp ID (required) |
corp_secret | - | Corp secret สำหรับแอปที่สร้างเอง (required) |
agent_id | - | Agent ID ของแอปที่สร้างเอง (required) |
token | - | Callback verification token (required) |
encoding_aes_key | - | 43-character AES key สำหรับการเข้ารหัส callback (required) |
host | 0.0.0.0 | Bind address สำหรับ HTTP callback server |
port | 8645 | Port สำหรับ HTTP callback server |
path | /wecom/callback | URL path สำหรับ callback endpoint |
Multi-App Routing
สำหรับองค์กรที่รันแอปที่สร้างเองหลายแอป (เช่น ในแผนกหรือบริษัทย่อยที่แตกต่างกัน) ให้กำหนดค่ารายการ apps ใน config.yaml:
platforms:
wecom_callback:
enabled: true
extra:
host: "0.0.0.0"
port: 8645
apps:
- name: "dept-a"
corp_id: "ww_corp_a"
corp_secret: "secret-a"
agent_id: "1000002"
token: "token-a"
encoding_aes_key: "key-a-43-chars..."
- name: "dept-b"
corp_id: "ww_corp_b"
corp_secret: "secret-b"
agent_id: "1000003"
token: "token-b"
encoding_aes_key: "key-b-43-chars..."ผู้ใช้จะถูกจำกัดขอบเขตด้วย corp_id:user_id เพื่อป้องกันการชนกันข้ามองค์กร เมื่อผู้ใช้ส่งข้อความ adapter จะบันทึกว่าผู้ใช้คนนั้นสังกัดแอป (corp) ใด และจะกำหนดเส้นทางคำตอบกลับผ่าน access token ของแอปที่ถูกต้อง
Access Control
จำกัดว่าผู้ใช้คนใดสามารถโต้ตอบกับแอปได้:
# อนุญาตเฉพาะผู้ใช้ที่ระบุ
WECOM_CALLBACK_ALLOWED_USERS=zhangsan,lisi,wangwu
# หรืออนุญาตผู้ใช้ทั้งหมด
WECOM_CALLBACK_ALLOW_ALL_USERS=trueEndpoints
adapter เปิดเผย:
| Method | Path | Purpose |
|---|---|---|
| GET | /wecom/callback | URL verification handshake (WeCom ส่งมาในช่วงตั้งค่า) |
| POST | /wecom/callback | Encrypted message callback (WeCom ส่งข้อความผู้ใช้มาที่นี่) |
| GET | /health | Health check - คืนค่า {"status": "ok"} |
Encryption
Payload callback ทั้งหมดจะถูกเข้ารหัสด้วย AES-CBC โดยใช้ EncodingAESKey adapter จะจัดการ:
- Inbound: ถอดรหัส XML payload, ตรวจสอบลายเซ็น SHA1
- Outbound: การตอบกลับที่ส่งผ่าน proactive API (ไม่ใช่การตอบกลับ callback ที่เข้ารหัส)
การใช้งาน crypto นี้เข้ากันได้กับ WXBizMsgCrypt SDK อย่างเป็นทางการของ Tencent
ข้อจำกัด
- ไม่มีการสตรีม (No streaming) - การตอบกลับจะมาถึงเป็นข้อความที่สมบูรณ์หลังจาก agent ทำงานเสร็จสิ้น
- ไม่มีตัวบ่งชี้การพิมพ์ (No typing indicators) - โมเดล callback ไม่รองรับสถานะการพิมพ์
- ข้อความเท่านั้น (Text only) - ปัจจุบันรองรับข้อความตัวอักษรสำหรับการป้อนข้อมูล; ยังไม่ได้ใช้งาน input รูปภาพ/ไฟล์/เสียง agent รับรู้ถึงความสามารถด้านสื่อขาออกผ่าน WeCom platform hint (รูปภาพ, เอกสาร, วิดีโอ, เสียง)
- ความหน่วงในการตอบกลับ (Response latency) - session ของ agent ใช้เวลา 3-30 นาที; ผู้ใช้จะเห็นการตอบกลับเมื่อการประมวลผลเสร็จสมบูรณ์
📄 user-guide/messaging/weixin.md
sidebar_position: 15 title: "Weixin (WeChat)" description: "Connect Hermes Agent to personal WeChat accounts via the iLink Bot API"
Weixin (WeChat)
เชื่อมต่อ Hermes กับ WeChat (微信) ซึ่งเป็นแพลตฟอร์มส่งข้อความส่วนตัวของ Tencent อะแดปเตอร์นี้ใช้ iLink Bot API ของ Tencent สำหรับบัญชี WeChat ส่วนตัว ซึ่งแตกต่างจาก WeCom (Enterprise WeChat) ข้อความจะถูกส่งผ่าน long-polling ดังนั้นจึงไม่จำเป็นต้องมี public endpoint หรือ webhook
:::info อะแดปเตอร์นี้สำหรับ บัญชี WeChat ส่วนตัว (微信) หากคุณต้องการ WeChat สำหรับองค์กร/บริษัท โปรดดูที่ WeCom adapter แทน :::
Prerequisites
- บัญชี WeChat ส่วนตัว
- Python packages:
aiohttpและcryptography - มีการรวมการเรนเดอร์ QR code ใน Terminal เมื่อติดตั้ง Hermes ด้วย extra
messaging
ติดตั้ง dependencies ที่จำเป็น:
pip install aiohttp cryptography
# Optional: for terminal QR code display
pip install hermes-agent[messaging]Setup
1. Run the Setup Wizard
วิธีที่ง่ายที่สุดในการเชื่อมต่อบัญชี WeChat ของคุณคือการใช้ setup แบบโต้ตอบ:
hermes gateway setupเลือก Weixin เมื่อระบบแจ้งเตือน Wizard จะดำเนินการดังนี้:
- ขอ QR code จาก iLink Bot API
- แสดง QR code ใน terminal ของคุณ (หรือให้ URL)
- รอให้คุณสแกน QR code ด้วยแอปพลิเคชัน WeChat บนมือถือ
- แจ้งให้คุณยืนยันการเข้าสู่ระบบบนโทรศัพท์ของคุณ
- บันทึก credentials ของบัญชีโดยอัตโนมัติไปยัง
~/.hermes/weixin/accounts/
เมื่อยืนยันแล้ว คุณจะเห็นข้อความประมาณว่า:
微信连接成功,account_id=your-account-idWizard จะจัดเก็บ account_id, token, และ base_url เพื่อที่คุณจะได้ไม่ต้องกำหนดค่าเหล่านี้ด้วยตนเอง
2. Configure Environment Variables
หลังจากเข้าสู่ระบบด้วย QR code ครั้งแรก ให้ตั้งค่าอย่างน้อย account ID ใน ~/.hermes/.env:
WEIXIN_ACCOUNT_ID=your-account-id
# Optional: override the token (normally auto-saved from QR login)
# WEIXIN_TOKEN=your-bot-token
# Optional: restrict access
WEIXIN_DM_POLICY=open
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2
# Optional: restore legacy multiline splitting behavior
# WEIXIN_SPLIT_MULTILINE_MESSAGES=true
# Optional: home channel for cron/notifications
WEIXIN_HOME_CHANNEL=chat_id
WEIXIN_HOME_CHANNEL_NAME=Home3. Start the Gateway
hermes gatewayอะแดปเตอร์จะกู้คืน credentials ที่บันทึกไว้ เชื่อมต่อกับ iLink API และเริ่ม long-polling สำหรับข้อความ
Features
- Long-poll transport - ไม่ต้องมี public endpoint, webhook, หรือ WebSocket
- QR code login - ตั้งค่าแบบ scan-to-connect ผ่าน
hermes gateway setup - DM and group messaging - นโยบายการเข้าถึงที่กำหนดค่าได้
- Media support - รองรับรูปภาพ วิดีโอ ไฟล์ และข้อความเสียง
- AES-128-ECB encrypted CDN - การเข้ารหัส/ถอดรหัสอัตโนมัติสำหรับการถ่ายโอนสื่อทั้งหมด
- Context token persistence - ความต่อเนื่องในการตอบกลับที่รองรับ disk-backed แม้จะรีสตาร์ท
- Markdown formatting - รักษา Markdown รวมถึง headers, tables, และ code blocks ทำให้ WeChat clients ที่รองรับ Markdown สามารถเรนเดอร์ได้โดยธรรมชาติ
- Smart message chunking - ข้อความจะยังคงเป็น bubble เดียวเมื่ออยู่ภายใต้ขีดจำกัด; มีเพียง payload ที่มีขนาดใหญ่เกินไปเท่านั้นที่ถูกแบ่งที่ขอบเขตเชิงตรรกะ
- Typing indicators - แสดงสถานะ "กำลังพิมพ์…" ใน WeChat client ขณะที่ agent กำลังประมวลผล
- SSRF protection - URL สื่อขาออกจะถูกตรวจสอบก่อนดาวน์โหลด
- Message deduplication - หน้าต่างเลื่อน 5 นาที ป้องกันการประมวลผลซ้ำ
- Automatic retry with backoff - กู้คืนจากข้อผิดพลาด API ชั่วคราว
Configuration Options
ตั้งค่าเหล่านี้ใน config.yaml ภายใต้ platforms.weixin.extra:
| Key | Default | Description |
|---|---|---|
account_id | — | iLink Bot account ID (required) |
token | — | iLink Bot token (required, auto-saved from QR login) |
base_url | https://ilinkai.weixin.qq.com | iLink API base URL |
cdn_base_url | https://novac2c.cdn.weixin.qq.com/c2c | CDN base URL สำหรับการถ่ายโอนสื่อ |
dm_policy | open | การเข้าถึง DM: open, allowlist, disabled, pairing |
group_policy | disabled | การเข้าถึงกลุ่ม: open, allowlist, disabled |
allow_from | [] | User IDs ที่อนุญาตสำหรับ DM (เมื่อ dm_policy=allowlist) |
group_allow_from | [] | Group IDs ที่อนุญาต (เมื่อ group_policy=allowlist) |
split_multiline_messages | false | เมื่อเป็น true จะแบ่งข้อความหลายบรรทัดเป็นการแชทหลายข้อความ (พฤติกรรมเดิม). เมื่อเป็น false จะเก็บข้อความหลายบรรทัดเป็นข้อความเดียว เว้นแต่จะเกินขีดจำกัดความยาว |
Access Policies
DM Policy
ควบคุมว่าใครสามารถส่ง direct messages ถึง bot ได้:
| Value | Behavior |
|---|---|
open | ทุกคนสามารถ DM bot ได้ (ค่าเริ่มต้น) |
allowlist | เฉพาะ user IDs ใน allow_from เท่านั้นที่สามารถ DM ได้ |
disabled | เพิกเฉยต่อ DM ทั้งหมด |
pairing | โหมดจับคู่ (สำหรับการตั้งค่าเริ่มต้น) |
WEIXIN_DM_POLICY=allowlist
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2Group Policy
ควบคุมว่า bot จะตอบกลับในกลุ่มใด:
| Value | Behavior |
|---|---|
open | bot ตอบกลับในทุกกลุ่ม |
allowlist | bot ตอบกลับเฉพาะ group IDs ที่ระบุใน group_allow_from |
disabled | เพิกเฉยต่อข้อความกลุ่มทั้งหมด (ค่าเริ่มต้น) |
WEIXIN_GROUP_POLICY=allowlist
WEIXIN_GROUP_ALLOWED_USERS=group_id_1,group_id_2:::note
ค่า default group policy คือ disabled สำหรับ Weixin (แตกต่างจาก WeCom ที่ default เป็น open) นี่เป็นสิ่งที่ตั้งใจไว้ เนื่องจากบัญชี WeChat ส่วนตัวอาจอยู่ในหลายกลุ่ม
:::
Media Support
Inbound (รับ)
อะแดปเตอร์จะรับ media attachments จากผู้ใช้ ดาวน์โหลดจาก WeChat CDN ถอดรหัส และแคชไว้ในเครื่องสำหรับการประมวลผลของ agent:
| Type | How it's handled |
|---|---|
| Images | ดาวน์โหลด, ถอดรหัส AES, และแคชเป็น JPEG |
| Video | ดาวน์โหลด, ถอดรหัส AES, และแคชเป็น MP4 |
| Files | ดาวน์โหลด, ถอดรหัส AES, และแคช รักษาชื่อไฟล์เดิม |
| Voice | หากมี text transcription จะถูกดึงออกมาเป็นข้อความ มิฉะนั้นจะดาวน์โหลดและแคช audio (รูปแบบ SILK) |
Quoted messages: สื่อจากข้อความที่ถูกอ้างถึง (replied-to) ก็จะถูกดึงออกมาด้วย เพื่อให้ agent มีบริบทว่าผู้ใช้กำลังตอบกลับอะไร
AES-128-ECB Encrypted CDN
ไฟล์สื่อ WeChat จะถูกถ่ายโอนผ่าน CDN ที่เข้ารหัส อะแดปเตอร์จัดการเรื่องนี้อย่างโปร่งใส:
- Inbound: สื่อที่เข้ารหัสจะถูกดาวน์โหลดจาก CDN โดยใช้ URL
encrypted_query_paramจากนั้นถอดรหัสด้วย AES-128-ECB โดยใช้ key ต่อไฟล์ที่ระบุใน message payload - Outbound: ไฟล์จะถูกเข้ารหัสในเครื่องด้วย key แบบสุ่ม AES-128-ECB และอัปโหลดไปยัง CDN จากนั้นจึงรวม encrypted reference ไว้ในข้อความขาออก
- AES key คือ 16 bytes (128-bit). Keys อาจมาในรูปแบบ raw base64 หรือ hex-encoded - อะแดปเตอร์จัดการทั้งสองรูปแบบ
- สิ่งนี้ต้องใช้ Python package
cryptography
ไม่จำเป็นต้องตั้งค่าใดๆ - การเข้ารหัสและการถอดรหัสจะเกิดขึ้นโดยอัตโนมัติ
Outbound (ส่ง)
| Method | What it sends |
|---|---|
send | ข้อความข้อความพร้อม Markdown formatting |
send_image / send_image_file | ข้อความรูปภาพแบบ Native (ผ่านการอัปโหลด CDN) |
send_document | ไฟล์ attachments (ผ่านการอัปโหลด CDN) |
send_video | ข้อความวิดีโอ (ผ่านการอัปโหลด CDN) |
สื่อขาออกทั้งหมดจะผ่านกระบวนการ upload encrypted CDN:
- สร้าง AES-128 key แบบสุ่ม
- เข้ารหัสไฟล์ด้วย AES-128-ECB + PKCS#7 padding
- ขอ upload URL จาก iLink API (
getuploadurl) - อัปโหลด ciphertext ไปยัง CDN
- ส่งข้อความพร้อม encrypted media reference
Context Token Persistence
iLink Bot API ต้องการ context_token เพื่อสะท้อนกลับไปพร้อมกับข้อความขาออกแต่ละข้อความสำหรับ peer ที่กำหนด อะแดปเตอร์จะรักษาสถานที่จัดเก็บ context token ที่รองรับ disk:
- Tokens จะถูกบันทึกต่อ account+peer ที่
~/.hermes/weixin/accounts/<account_id>.context-tokens.json - เมื่อเริ่มต้น จะกู้คืน tokens ที่บันทึกไว้ก่อนหน้า
- ทุกข้อความขาเข้าจะอัปเดต token ที่จัดเก็บสำหรับผู้ส่งนั้น
- ข้อความขาออกจะรวม context token ล่าสุดโดยอัตโนมัติ
สิ่งนี้รับประกันความต่อเนื่องในการตอบกลับแม้หลังจากที่ gateway รีสตาร์ท
Markdown Formatting
WeChat clients ที่เชื่อมต่อผ่าน iLink Bot API สามารถเรนเดอร์ Markdown ได้โดยตรง ดังนั้นอะแดปเตอร์จึงรักษา Markdown ไว้แทนการเขียนใหม่:
- Headers ยังคงเป็น Markdown headings (
#,##, ...) - Tables ยังคงเป็น Markdown tables
- Code fences ยังคงเป็น fenced code blocks
- Excessive blank lines จะถูกยุบเป็น double newlines นอก fenced code blocks
Message Chunking
ข้อความจะถูกส่งเป็นแชทข้อความเดียวเมื่ออยู่ในขีดจำกัดของแพลตฟอร์ม มีเพียง payload ที่มีขนาดใหญ่เกินไปเท่านั้นที่ถูกแบ่งเพื่อการส่ง:
- ความยาวข้อความสูงสุด: 4000 characters
- ข้อความที่ต่ำกว่าขีดจำกัดจะยังคงสมบูรณ์แม้ว่าจะมีหลายย่อหน้าหรือการขึ้นบรรทัดใหม่
- ข้อความขนาดใหญ่เกินไปจะถูกแบ่งที่ขอบเขตเชิงตรรกะ (ย่อหน้า, บรรทัดว่าง, code fences)
- Code fences จะถูกเก็บไว้ให้สมบูรณ์เมื่อเป็นไปได้ (จะไม่ถูกแบ่งกลางบล็อก เว้นแต่ตัว fence เองจะเกินขีดจำกัด)
- บล็อกเดี่ยวที่มีขนาดใหญ่เกินไปจะใช้ logic การตัดทอนของอะแดปเตอร์พื้นฐาน
- การหน่วงเวลา inter-chunk 0.3 s ป้องกันการลด rate-limit ของ WeChat เมื่อมีการส่งหลาย chunks
Typing Indicators
อะแดปเตอร์แสดงสถานะการพิมพ์ใน WeChat client:
- เมื่อข้อความมาถึง อะแดปเตอร์จะดึง
typing_ticketผ่าน APIgetconfig - Typing tickets จะถูกแคชเป็นเวลา 10 นาทีต่อผู้ใช้
send_typingส่งสัญญาณเริ่มพิมพ์;stop_typingส่งสัญญาณหยุดพิมพ์- gateway จะกระตุ้น typing indicators โดยอัตโนมัติในขณะที่ agent กำลังประมวลผลข้อความ
Long-Poll Connection
อะแดปเตอร์ใช้ HTTP long-polling (ไม่ใช่ WebSocket) เพื่อรับข้อความ:
How It Works
- Connect: ตรวจสอบ credentials และเริ่ม poll loop
- Poll: เรียก
getupdatesด้วย timeout 35 วินาที; server จะคงคำขอไว้จนกว่าข้อความจะมาถึงหรือหมดเวลา - Dispatch: ข้อความขาเข้าจะถูก dispatch แบบ concurrent ผ่าน
asyncio.create_task - Sync buffer: sync cursor แบบถาวร (
get_updates_buf) จะถูกบันทึกใน disk เพื่อให้อะแดปเตอร์สามารถดำเนินการต่อจากตำแหน่งที่ถูกต้องหลังจากการรีสตาร์ท
Retry Behavior
เมื่อเกิดข้อผิดพลาด API อะแดปเตอร์ใช้กลยุทธ์การ retry แบบง่าย:
| Condition | Behavior |
|---|---|
| Transient error (1st–2nd) | Retry after 2 seconds |
| Repeated errors (3+) | Back off for 30 seconds, then reset counter |
Session expired (errcode=-14) | Pause for 10 minutes (อาจต้อง re-login) |
| Timeout | Re-poll ทันที (พฤติกรรม long-poll ปกติ) |
Deduplication
ข้อความขาเข้าจะถูก deduplicate โดยใช้ message IDs พร้อมหน้าต่าง 5 นาที สิ่งนี้ป้องกันการประมวลผลซ้ำระหว่างที่เครือข่ายมีปัญหาหรือการตอบกลับ poll ที่ทับซ้อนกัน
Token Lock
มีเพียง Weixin gateway instance เดียวเท่านั้นที่สามารถใช้ token ที่กำหนดได้ในเวลาใดเวลาหนึ่ง อะแดปเตอร์จะเข้าถึง scoped lock เมื่อเริ่มต้นและปล่อยเมื่อปิด หาก gateway อื่นกำลังใช้ token เดียวกันอยู่ การเริ่มต้นจะล้มเหลวพร้อมข้อความ error ที่ให้ข้อมูล
All Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
WEIXIN_ACCOUNT_ID | ✅ | — | iLink Bot account ID (จาก QR login) |
WEIXIN_TOKEN | ✅ | — | iLink Bot token (auto-saved from QR login) |
WEIXIN_BASE_URL | — | https://ilinkai.weixin.qq.com | iLink API base URL |
WEIXIN_CDN_BASE_URL | — | https://novac2c.cdn.weixin.qq.com/c2c | CDN base URL สำหรับการถ่ายโอนสื่อ |
WEIXIN_DM_POLICY | — | open | นโยบายการเข้าถึง DM: open, allowlist, disabled, pairing |
WEIXIN_GROUP_POLICY | — | disabled | นโยบายการเข้าถึงกลุ่ม: open, allowlist, disabled |
WEIXIN_ALLOWED_USERS | — | (empty) | User IDs คั่นด้วย comma สำหรับ DM allowlist |
WEIXIN_GROUP_ALLOWED_USERS | — | (empty) | Group IDs คั่นด้วย comma สำหรับ group allowlist |
WEIXIN_HOME_CHANNEL | — | — | Chat ID สำหรับ output ของ cron/notification |
WEIXIN_HOME_CHANNEL_NAME | — | Home | ชื่อที่แสดงสำหรับ home channel |
WEIXIN_ALLOW_ALL_USERS | — | — | Flag ระดับ Gateway เพื่ออนุญาตผู้ใช้ทั้งหมด (ใช้โดย setup wizard) |
Troubleshooting
| Problem | Fix |
|---|---|
Weixin startup failed: aiohttp and cryptography are required | ติดตั้งทั้งสองตัว: pip install aiohttp cryptography |
Weixin startup failed: WEIXIN_TOKEN is required | รัน hermes gateway setup เพื่อทำ QR login ให้เสร็จสมบูรณ์ หรือตั้งค่า WEIXIN_TOKEN ด้วยตนเอง |
Weixin startup failed: WEIXIN_ACCOUNT_ID is required | ตั้งค่า WEIXIN_ACCOUNT_ID ใน .env ของคุณ หรือรัน hermes gateway setup |
Another local Hermes gateway is already using this Weixin token | หยุด instance gateway อื่นก่อน - อนุญาตให้มี poller ได้เพียงตัวเดียวต่อ token |
Session expired (errcode=-14) | session login ของคุณหมดอายุแล้ว รัน hermes gateway setup ใหม่เพื่อสแกน QR code ใหม่ |
| QR code expired during setup | QR code จะรีเฟรชอัตโนมัติสูงสุด 3 ครั้ง หากยังคงหมดอายุ ให้ตรวจสอบการเชื่อมต่อเครือข่ายของคุณ |
| Bot doesn't respond to DMs | ตรวจสอบ WEIXIN_DM_POLICY - หากตั้งค่าเป็น allowlist ผู้ส่งต้องอยู่ใน WEIXIN_ALLOWED_USERS |
| Bot ignores group messages | group policy default เป็น disabled ตั้งค่า WEIXIN_GROUP_POLICY=open หรือ allowlist |
| Media download/upload fails | ตรวจสอบว่าติดตั้ง cryptography แล้วหรือไม่ ตรวจสอบการเข้าถึงเครือข่ายไปยัง novac2c.cdn.weixin.qq.com |
Blocked unsafe URL (SSRF protection) | URL สื่อขาออกชี้ไปยังที่อยู่ส่วนตัว/ภายใน มีเพียง URL สาธารณะเท่านั้นที่อนุญาต |
| Voice messages show as text | หาก WeChat ให้ transcription อะแดปเตอร์จะใช้ข้อความนี้ นี่คือพฤติกรรมที่คาดหวัง |
| Messages appear duplicated | อะแดปเตอร์จะ deduplicate ด้วย message ID หากคุณเห็นข้อความซ้ำ ให้ตรวจสอบว่ามี gateway instance หลายตัวกำลังทำงานอยู่หรือไม่ |
iLink POST ... HTTP 4xx/5xx | ข้อผิดพลาด API จากบริการ iLink ตรวจสอบความถูกต้องของ token และการเชื่อมต่อเครือข่ายของคุณ |
| Terminal QR code doesn't render | ติดตั้งใหม่ด้วย extra messaging: pip install hermes-agent[messaging]. หรือเปิด URL ที่พิมพ์ไว้เหนือ QR code |
📄 user-guide/messaging/whatsapp.md
sidebar_position: 5 title: "WhatsApp" description: "ตั้งค่า Hermes Agent เป็นบอท WhatsApp ผ่าน Baileys bridge ที่ติดตั้งมาให้"
การตั้งค่า WhatsApp
Hermes เชื่อมต่อกับ WhatsApp ผ่าน bridge ที่ติดตั้งมาให้ ซึ่งอ้างอิงจาก Baileys วิธีการทำงานคือการจำลองเซสชัน WhatsApp Web — ไม่ใช่ผ่าน WhatsApp Business API อย่างเป็นทางการ ไม่จำเป็นต้องมีบัญชี Meta developer หรือการยืนยันธุรกิจใดๆ
:::warning API ที่ไม่เป็นทางการ - ความเสี่ยงในการถูกแบน WhatsApp ไม่ได้รองรับบอทจากบุคคลที่สามอย่างเป็นทางการนอกเหนือจาก Business API การใช้ bridge จากบุคคลที่สามมีความเสี่ยงเล็กน้อยที่บัญชีจะถูกจำกัดการใช้งาน เพื่อลดความเสี่ยง:
- ใช้หมายเลขโทรศัพท์เฉพาะ สำหรับบอท (ไม่ใช่หมายเลขส่วนตัวของคุณ)
- ห้ามส่งข้อความจำนวนมาก/สแปม - ควรคงการใช้งานแบบสนทนา
- ห้ามทำระบบอัตโนมัติในการส่งข้อความขาออก ไปยังผู้ที่ไม่ได้ส่งข้อความมาก่อน :::
:::warning การอัปเดตโปรโตคอล WhatsApp Web WhatsApp มีการอัปเดตโปรโตคอล Web เป็นระยะ ซึ่งอาจทำให้ความเข้ากันได้กับ bridge จากบุคคลที่สามหยุดชะงักชั่วคราว เมื่อเกิดเหตุการณ์นี้ Hermes จะทำการอัปเดต dependency ของ bridge หากบอทหยุดทำงานหลังจากการอัปเดตของ WhatsApp ให้ดึงเวอร์ชันล่าสุดของ Hermes และทำการจับคู่ (re-pair) ใหม่ :::
สองโหมด
| โหมด | วิธีการทำงาน | เหมาะสำหรับ |
|---|---|---|
| หมายเลขบอทแยก (แนะนำ) | กำหนดหมายเลขโทรศัพท์สำหรับบอทโดยเฉพาะ ผู้คนจะส่งข้อความไปยังหมายเลขนั้นโดยตรง | ประสบการณ์ผู้ใช้ที่สะอาด, ผู้ใช้หลายคน, ความเสี่ยงในการถูกแบนต่ำ |
| แชทส่วนตัวด้วยตนเอง | ใช้ WhatsApp ของคุณเอง คุณส่งข้อความหาตัวเองเพื่อพูดคุยกับ agent | การตั้งค่าที่รวดเร็ว, ผู้ใช้คนเดียว, การทดสอบ |
สิ่งที่ต้องเตรียม (Prerequisites)
- Node.js v18+ และ npm - bridge WhatsApp ทำงานเป็น process ของ Node.js
- โทรศัพท์ที่มี WhatsApp ติดตั้งอยู่ (สำหรับสแกน QR code)
แตกต่างจาก bridge ที่ขับเคลื่อนด้วยเบราว์เซอร์รุ่นเก่า, bridge ที่ใช้ Baileys ในปัจจุบัน ไม่จำเป็นต้องมี dependency stack ของ Chromium หรือ Puppeteer ในเครื่อง
ขั้นตอนที่ 1: รัน Setup Wizard
hermes whatsappWizard จะ:
- สอบถามว่าต้องการโหมดใด (bot หรือ self-chat)
- ติดตั้ง dependency ของ bridge หากจำเป็น
- แสดง QR code ใน terminal ของคุณ
- รอให้คุณสแกน
วิธีสแกน QR code:
- เปิด WhatsApp บนโทรศัพท์ของคุณ
- ไปที่ Settings → Linked Devices
- แตะ Link a Device
- เล็งกล้องไปที่ QR code ใน terminal
เมื่อจับคู่สำเร็จ Wizard จะยืนยันการเชื่อมต่อและออกจากระบบ เซสชันของคุณจะถูกบันทึกโดยอัตโนมัติ
:::tip หาก QR code ดูผิดเพี้ยน ให้แน่ใจว่า terminal ของคุณมีความกว้างอย่างน้อย 60 คอลัมน์ และรองรับ Unicode คุณยังสามารถลองใช้ terminal emulator อื่นได้ :::
ขั้นตอนที่ 2: การหาหมายเลขโทรศัพท์เครื่องที่สอง (Bot Mode)
สำหรับโหมดบอท คุณต้องใช้หมายเลขโทรศัพท์ที่ยังไม่ได้ลงทะเบียนกับ WhatsApp มีสามตัวเลือก:
| ตัวเลือก | ค่าใช้จ่าย | หมายเหตุ |
|---|---|---|
| Google Voice | ฟรี | สำหรับสหรัฐฯ เท่านั้น รับหมายเลขได้ที่ voice.google.com ยืนยัน WhatsApp ผ่าน SMS ด้วยแอป Google Voice |
| ซิมเติมเงิน | $5–15 ครั้งเดียว | ผู้ให้บริการรายใดก็ได้ เปิดใช้งาน ยืนยัน WhatsApp จากนั้นซิมสามารถเก็บไว้ในลิ้นชักได้ หมายเลขต้องยังใช้งานอยู่ (โทรออกทุก 90 วัน) |
| บริการ VoIP | ฟรี–$5/เดือน | TextNow, TextFree หรือที่คล้ายกัน หมายเลข VoIP บางหมายเลขถูก WhatsApp บล็อก - ลองหลายๆ ตัวหากตัวแรกใช้ไม่ได้ |
หลังจากได้หมายเลขแล้ว:
- ติดตั้ง WhatsApp บนโทรศัพท์ (หรือใช้แอป WhatsApp Business แบบ dual-SIM)
- ลงทะเบียนหมายเลขใหม่กับ WhatsApp
- รัน
hermes whatsappและสแกน QR code จากบัญชี WhatsApp นั้น
ขั้นตอนที่ 3: กำหนดค่า Hermes
เพิ่มสิ่งต่อไปนี้ในไฟล์ ~/.hermes/.env ของคุณ:
# Required
WHATSAPP_ENABLED=true
WHATSAPP_MODE=bot # "bot" หรือ "self-chat"
# การควบคุมการเข้าถึง - เลือกตัวเลือกใดตัวเลือกหนึ่ง:
WHATSAPP_ALLOWED_USERS=15551234567 # หมายเลขโทรศัพท์ที่คั่นด้วยเครื่องหมายจุลภาค (พร้อมรหัสประเทศ, ห้ามมี +)
# WHATSAPP_ALLOWED_USERS=* # หรือใช้ * เพื่ออนุญาตทุกคน
# WHATSAPP_ALLOW_ALL_USERS=true # หรือตั้งค่า flag นี้แทน (ผลลัพธ์เหมือนกับ *):::tip Allow-all shorthand
การตั้งค่า WHATSAPP_ALLOWED_USERS=* อนุญาตให้ผู้ส่ง ทุกคน (เทียบเท่ากับ WHATSAPP_ALLOW_ALL_USERS=true)
สิ่งนี้สอดคล้องกับ Signal group allowlists
หากต้องการใช้ flow การจับคู่ (pairing flow) แทน ให้ลบทั้งสองตัวแปรออกและพึ่งพา
ระบบการจับคู่ DM
:::
การตั้งค่าพฤติกรรมเสริมใน ~/.hermes/config.yaml:
unauthorized_dm_behavior: pair
whatsapp:
unauthorized_dm_behavior: ignoreunauthorized_dm_behavior: pairคือค่าเริ่มต้นทั่วโลก ผู้ส่ง DM ที่ไม่รู้จักจะได้รับรหัสจับคู่whatsapp.unauthorized_dm_behavior: ignoreทำให้ WhatsApp เงียบสำหรับ DM ที่ไม่ได้รับอนุญาต ซึ่งโดยทั่วไปเป็นตัวเลือกที่ดีกว่าสำหรับหมายเลขส่วนตัว
จากนั้นเริ่ม gateway:
hermes gateway # Foreground
hermes gateway install # ติดตั้งเป็น user service
sudo hermes gateway install --system # สำหรับ Linux เท่านั้น: system service ที่บูตเครื่องgateway จะเริ่ม bridge WhatsApp โดยอัตโนมัติโดยใช้เซสชันที่บันทึกไว้
การคงอยู่ของเซสชัน (Session Persistence)
bridge Baileys จะบันทึกเซสชันภายใต้ ~/.hermes/platforms/whatsapp/session ซึ่งหมายความว่า:
- เซสชันอยู่รอดแม้จะรีสตาร์ท - คุณไม่จำเป็นต้องสแกน QR code ใหม่ทุกครั้ง
- ข้อมูลเซสชันรวมถึงคีย์การเข้ารหัสและ credentials ของอุปกรณ์
- ห้ามแชร์หรือ commit directory เซสชันนี้ - เพราะมันให้สิทธิ์การเข้าถึงบัญชี WhatsApp อย่างสมบูรณ์
การจับคู่ใหม่ (Re-pairing)
หากเซสชันขาด (รีเซ็ตโทรศัพท์, อัปเดต WhatsApp, ยกเลิกการเชื่อมต่อด้วยตนเอง) คุณจะเห็นข้อผิดพลาดการเชื่อมต่อใน log ของ gateway หากต้องการแก้ไข:
hermes whatsappสิ่งนี้จะสร้าง QR code ใหม่ สแกนอีกครั้งและเซสชันจะถูกสร้างขึ้นใหม่ gateway จะจัดการการตัดการเชื่อมต่อ ชั่วคราว (network blips, โทรศัพท์ออฟไลน์ชั่วคราว) โดยอัตโนมัติด้วย logic การเชื่อมต่อใหม่
ข้อความเสียง (Voice Messages)
Hermes รองรับข้อความเสียงบน WhatsApp:
- ขาเข้า: ข้อความเสียง (
.oggopus) จะถูกถอดเสียงโดยอัตโนมัติโดยใช้ STT provider ที่กำหนดค่าไว้: localfaster-whisper, Groq Whisper (GROQ_API_KEY), หรือ OpenAI Whisper (VOICE_TOOLS_OPENAI_KEY) - ขาออก: การตอบกลับแบบ TTS จะถูกส่งเป็นไฟล์แนบเสียง MP3
- การตอบกลับของ Agent จะมีคำนำหน้าด้วย "⚕ Hermes Agent" โดยค่าเริ่มต้น คุณสามารถปรับแต่งหรือปิดใช้งานสิ่งนี้ได้ใน
config.yaml:
# ~/.hermes/config.yaml
whatsapp:
reply_prefix: "" # ข้อความว่างเปล่าจะปิด header
# reply_prefix: "🤖 *My Bot*\n──────\n" # Custom prefix (รองรับ \n สำหรับการขึ้นบรรทัดใหม่)การจัดรูปแบบและการส่งข้อความ (Message Formatting & Delivery)
WhatsApp รองรับ การตอบกลับแบบสตรีมมิง (progressive responses) - บอทจะแก้ไขข้อความของตัวเองแบบเรียลไทม์ขณะที่ AI สร้างข้อความ เช่นเดียวกับ Discord และ Telegram ภายในแล้ว WhatsApp ถูกจัดประเภทเป็นแพลตฟอร์ม TIER_MEDIUM สำหรับความสามารถในการส่งมอบ
Chunking
การตอบกลับที่ยาวจะถูกแบ่งออกเป็นหลายข้อความโดยอัตโนมัติที่ 4,096 ตัวอักษร ต่อ chunk (ขีดจำกัดการแสดงผลที่ใช้งานได้จริงของ WhatsApp) คุณไม่จำเป็นต้องกำหนดค่าใดๆ - gateway จะจัดการการแบ่งและส่ง chunks ตามลำดับ
Markdown ที่เข้ากันได้กับ WhatsApp
Markdown มาตรฐานในการตอบกลับ AI จะถูกแปลงเป็นรูปแบบเนทีฟของ WhatsApp โดยอัตโนมัติ:
| Markdown | แสดงผลเป็น | |
|---|---|---|
**bold** | *bold* | bold |
~~strikethrough~~ | ~strikethrough~ | |
# Heading | *Heading* | ข้อความตัวหนา (ไม่มี heading เนทีฟ) |
[link text](url) | link text (url) | Inline URL |
Code blocks และ inline code จะถูกเก็บไว้ตามเดิม เนื่องจาก WhatsApp รองรับการจัดรูปแบบแบบ triple-backtick โดยเนทีฟ
Tool Progress
เมื่อ agent เรียกใช้ tools (web search, file operations, etc.) WhatsApp จะแสดงตัวบ่งชี้ความคืบหน้าแบบเรียลไทม์ว่า tool ใดกำลังทำงานอยู่ สิ่งนี้เปิดใช้งานโดยค่าเริ่มต้น - ไม่ต้องกำหนดค่าใดๆ
การแก้ไขปัญหา (Troubleshooting)
| ปัญหา | วิธีแก้ไข |
|---|---|
| QR code สแกนไม่ได้ | ตรวจสอบให้แน่ใจว่า terminal กว้างพอ (60+ คอลัมน์) ลองใช้ terminal อื่น ตรวจสอบให้แน่ใจว่าคุณสแกนจากบัญชี WhatsApp ที่ถูกต้อง (หมายเลขบอท ไม่ใช่ส่วนตัว) |
| QR code หมดอายุ | QR code จะรีเฟรชทุกๆ ~20 วินาที หากหมดเวลา ให้รีสตาร์ท hermes whatsapp |
| เซสชันไม่คงอยู่ | ตรวจสอบว่า ~/.hermes/platforms/whatsapp/session มีอยู่และสามารถเขียนได้ หากใช้ container ให้ mount เป็น persistent volume |
| ออกจากระบบโดยไม่คาดคิด | WhatsApp จะยกเลิกการเชื่อมต่ออุปกรณ์หลังจากไม่มีการใช้งานเป็นเวลานาน ให้เปิดโทรศัพท์และเชื่อมต่อเครือข่ายไว้ จากนั้นทำการจับคู่ใหม่ด้วย hermes whatsapp หากจำเป็น |
| Bridge ล่มหรือวนลูปการเชื่อมต่อใหม่ | รีสตาร์ท gateway, อัปเดต Hermes, และจับคู่ใหม่หากเซสชันถูกทำให้เป็นโมฆะโดยการเปลี่ยนแปลงโปรโตคอลของ WhatsApp |
| บอทหยุดทำงานหลังการอัปเดต WhatsApp | อัปเดต Hermes เพื่อรับ bridge เวอร์ชันล่าสุด จากนั้นทำการจับคู่ใหม่ |
| macOS: "Node.js not installed" แต่ node ทำงานใน terminal | บริการ launchd ไม่ได้สืบทอด PATH ของ shell ของคุณ รัน hermes gateway install เพื่อบันทึก PATH ปัจจุบันของคุณลงใน plist จากนั้น hermes gateway start ดู Gateway Service docs สำหรับรายละเอียด |
| ไม่ได้รับข้อความ | ตรวจสอบว่า WHATSAPP_ALLOWED_USERS รวมถึงหมายเลขของผู้ส่ง (พร้อมรหัสประเทศ, ห้ามมี + หรือช่องว่าง) หรือตั้งค่าเป็น * เพื่ออนุญาตทุกคน ตั้งค่า WHATSAPP_DEBUG=true ใน .env และรีสตาร์ท gateway เพื่อดู event ข้อความดิบใน bridge.log |
| บอทตอบผู้แปลกหน้าด้วยรหัสจับคู่ | ตั้งค่า whatsapp.unauthorized_dm_behavior: ignore ใน ~/.hermes/config.yaml หากคุณต้องการให้ DM ที่ไม่ได้รับอนุญาตถูกเพิกเฉยอย่างเงียบๆ แทน |
ความปลอดภัย (Security)
:::warning
กำหนดค่าการควบคุมการเข้าถึง ก่อนใช้งานจริง ตั้งค่า WHATSAPP_ALLOWED_USERS ด้วยหมายเลขโทรศัพท์ที่เฉพาะเจาะจง (รวมรหัสประเทศ, ห้ามมี +) ใช้ * เพื่ออนุญาตทุกคน หรือตั้งค่า WHATSAPP_ALLOW_ALL_USERS=true หากไม่มีการตั้งค่าใดๆ gateway จะ ปฏิเสธข้อความขาเข้าทั้งหมด เพื่อความปลอดภัย
:::
โดยค่าเริ่มต้น, DM ที่ไม่ได้รับอนุญาตยังคงได้รับคำตอบเป็นรหัสจับคู่ หากคุณต้องการให้หมายเลข WhatsApp ส่วนตัวเงียบสนิทกับคนแปลกหน้า ให้ตั้งค่า:
whatsapp:
unauthorized_dm_behavior: ignore- directory
~/.hermes/platforms/whatsapp/sessionบรรจุ credentials ของเซสชันทั้งหมด - โปรดปกป้องมันเหมือนรหัสผ่าน - ตั้งค่าสิทธิ์ไฟล์:
chmod 700 ~/.hermes/platforms/whatsapp/session - ใช้ หมายเลขโทรศัพท์เฉพาะ สำหรับบอทเพื่อแยกความเสี่ยงจากบัญชีส่วนตัวของคุณ
- หากสงสัยว่าถูกบุกรุก ให้ยกเลิกการเชื่อมต่ออุปกรณ์จาก WhatsApp → Settings → Linked Devices
- หมายเลขโทรศัพท์ใน log จะถูกปกปิดบางส่วน แต่โปรดตรวจสอบนโยบายการเก็บรักษา log ของคุณ
extent analysis
TL;DR
- แก้ไขปัญหาการเชื่อมต่อ WhatsApp โดยตรวจสอบให้แน่ใจว่า QR code ถูกสแกนจากบัญชี WhatsApp ที่ถูกต้อง (หมายเลขบอท ไม่ใช่ส่วนตัว) และตรวจสอบว่า
~/.hermes/platforms/whatsapp/sessionมีอยู่และสามารถเขียนได้
Guidance
- ตรวจสอบการเชื่อมต่ออุปกรณ์: ตรวจสอบว่าอุปกรณ์โทรศัพท์ของคุณเชื่อมต่อกับอินเทอร์เน็ตและเปิดใช้งาน WhatsApp
- รีสตาร์ท gateway: รีสตาร์ท gateway และทำการจับคู่ใหม่ด้วย
hermes whatsappหากจำเป็น - อัปเดต Hermes: อัปเดต Hermes เพื่อรับ bridge เวอร์ชันล่าสุด
- ตรวจสอบ log: ตรวจสอบ log ของ gateway เพื่อหาสาเหตุของปัญหา
Example
hermes whatsappสิ่งนี้จะสร้าง QR code ใหม่และช่วยให้คุณจับคู่อีกครั้ง
Notes
- ตรวจสอบให้แน่ใจว่าได้ตั้งค่า
WHATSAPP_ALLOWED_USERSด้วยหมายเลขโทรศัพท์ที่เฉพาะเจาะจง (รวมรหัสประเทศ, ห้ามมี+) หรือตั้งค่าเป็น*เพื่ออนุญาตทุกคน - ใช้
WHATSAPP_ALLOW_ALL_USERS=trueหากต้องการอนุญาตทุกคน
Recommendation
- อัปเดต Hermes เพื่อรับ bridge เวอร์ชันล่าสุดและแก้ไขปัญหาการเชื่อมต่อ WhatsApp
- ตรวจสอบให้แน่ใจว
Vote matrix · Quick signals
Still need to ship something?
×6Another batch ranked right after the header list — different links, same matching logic.
TRENDING
- Feature Request: Configurable per-minute rate limiting (RPM) for models to prevent 429 errors
- Android: Hermes App + Termux install share ~/.hermes and cause silent permission loops
- hermes update emits unicode-animations ANSI demo in non-interactive logs
- hermes update downgrades aiohttp from 3.13.4 to 3.13.3
- npm install warns about deprecated @babel/plugin-proposal-private-methods
- DingTalk inbound media URLs are skipped as unreadable native image paths
- fix(dashboard): ChatPage clears header action buttons on ALL pages, not just Sessions
- [Bug]: check_web_api_key() hardcodes built-in backends — third-party web search plugins silently disabled
- Hermes Web UI 修复经验:GatewayManager 补丁、进程 D 状态、数据库升级问题
- Telegram gateway can silently drop turn after /stop with response=0 chars while internal work continues
- Bug Report: v0.14.0 上下文污染 — 历史回复碎片回注到新请求
- Bug: hermes skills search table truncates Identifier column — install fails with copied value
- [skills-index-watchdog] Skills index is stale or degraded (degraded)
- Discord approval embed not rendering on web/mobile — embed data present in API but invisible
- Idea: Discord voice-channel participation / opt-in auto-join mode
- [Feature]: Claude Code--ultrawork
- build-arm64 job deterministically fails on cold cache (Azure SAS token expires mid-build)
- [Enhancement] computer_use: action=type should fall back to key events for terminal emulators (Ghostty/Terminal.app/iTerm2)
- Feature Request: Session Recovery on Temporary Provider Outage
- [Bug]: Hermes dashboard not working on NixOS (container)
- [Feature]: Add option to ignore @all/@everyone mentions in Feishu group chats
- QQ Bot WebSocket 频繁断开:长时间工具执行阻塞 asyncio 事件循环导致心跳超时
- patch tool: new_string escape sequences (\t) get written literally
- Feature Request: i18n / 多语言支持(国际化)
- Bug: web_crawl schema lets models auto-guess "instructions" instead of asking the user via clarify
- feat: `!command` prefix for direct shell execution (like Claude Code)
- Expose currently-running cron jobs via /api/jobs (or new endpoint)
- [Bug]: Kanban parent-child handoff: scratch workspace GC destroys artifacts before child can read them
- [Bug, Windows] hermes gateway restart loses session context — planned_stop_marker not written before SIGTERM
- [Bug]: Codex→DeepSeek fallback sends assistant turns without reasoning_content → HTTP 400 (require-side cross-provider failover)
- [Bug]: Update got stuck half way, reboot it, then ModuleNotFoundError: No module named 'hermes_cli'
- Kanban dispatcher corrupt-board handling and multi-profile gateway ownership ambiguity
- Gateway can resend a short fallback message when the real final Telegram response was already delivered
- [BUG] Bedrock: Fix 'Invalid API Key format' for presigned URL tokens
- Secret redaction corrupts code syntax in tool output (write_file, execute_code, terminal)
- Unable to connect Ollama Cloud with Pro Subscription to Hermes
- feat: fuzzy substring matching for /skill autocomplete
- PRD: Autonomous market-impact prediction briefing system
- Kanban dashboard should support task/card deep links
- [Feature] Native Feishu CardKit Streaming: consolidate best-in-class implementations
- [Feature]: Inject mental model into context when using Hindsight
- Interactive CLI hides tool output despite display.tool_progress=all, and hermes chat -v does not restore it
- fix(api_server): _handle_responses drops text.format JSON schema — structured output constraints silently ignored
- state.db FTS corruption goes undetected — no integrity check, no repair path
- bug: fallback routing can select text-only models for image requests and hide the primary failure
- feat(kanban): persist worker session_id per run and pass --resume on respawn after unblock
- feat(kanban): support GitHub/OMO lifecycle bridge for Xiyou-style automation
- Expose update-safe TUI/composer hooks for voice transcript and composer events
- Hide or configure voice transcript status rows in editable dictation mode
- [Feature]: Per-Tool / Per-Toolset Approval Policies
- Context compression creates orphan sessions missing from state.db
- messaging platform
- feat: Add read-only / silent monitoring mode for WhatsApp adapter
- double-.hermes path mismatch, the HOME env var leak, and the fallback-notification UX problem
- Bug: Plattform-Bundle name `hermes-yuanbao` in `agent.disabled_toolsets` silently kills ALL tools in gateway path (Telegram + cron), CLI unaffected
- CLI /yolo (in-chat) does not bypass dangerous command approvals — env var freeze + missing enable_session_yolo call
- OpenAI Codex provider crashes with "'NoneType' object is not iterable" (HTTP None)
- DEEPSEEK_API_KEY blocked by env blocklist in gateway process — cron jobs fail with deepseek provider
- fix(feishu): Card action callback routing issues - invalid message_id and unrecognized /card command
- Discord plugin: profiles without explicit `discord:` block silently get `require_mention=true` + `auto_thread=true` (regression in cc8e5ec2a)
- [Bug]: DISCORD_ALLOWED_ROLES ignored by gateway _is_user_authorized — role-authorized users get 'Unauthorized user' rejection
- [Bug]: /new, /clear, and /reset commands freeze the terminal session
- openai-codex subscription backend returns HTTP 200 with response.output=None, causing Slack/cron failures
- RFC: Centralized Model/Provider Registry
- bug: openai-codex provider — TypeError: 'NoneType' object is not iterable on every request (gpt-5.5)
- [Feature]: Source-aware instruction gate — architectural mitigation for indirect prompt injection
- Named custom provider stale_timeout_seconds ignored because runtime provider is normalized to `custom`
- guard test (ignore)
- [Feature]: per-platform LLM request_overrides (extra_body / reasoning_effort / service_tier)
- One-shot smoke: add Flue-backed orchestration fixture
- Gateway should not treat stale Codex app-server progress as final response after post-tool silence
- `docker_run_as_host_user: true` breaks bundled skills: Hermes home is mounted into `/root/.hermes` but the container runs as a non-root user (`HOME=/home/pn`)
- [Bug]: gateway api_server streaming bypasses server-side tool-call loop when chat_template_kwargs.enable_thinking=false (model emits tool name as plain text)
- [Feature]: Pre-install python-telegram-bot in Umbrel Hermes Docker image
- YouTube Shorts filter not working in youtube-content skill
- v0.15.0 PyPI release breaks ALL platforms — plugin.yaml manifests missing from package
- RFC: On-demand tool/skill/MCP discovery — decouple schema registration from process lifecycle
- Pixshelf: local-first stock photo workflow command center
- [Bug]: baoyu infographic skill should not silently bypass image_generate
- Pixshelf v1.5: manual submission tracking for stock agencies
- `hermes config set` silently accepts unknown keys, writing them where the runtime never reads
- Honcho memory prefetch hang on fresh CLI subprocess in v0.15.0 (regression from #27190)
- [Bug] v0.15.0 Docker image: stage2-hook.sh, main-wrapper.sh missing; container_boot module removed
- Feature: Reduce cache-read token overhead for DeepSeek providers — configurable cache_ttl, skills snapshot trimming, memory compaction
- Windows: three bugs from daily use (plugin discovery, gateway exit code, Unicode decode
- holographic memory: HRR silently degrades to FTS5 when numpy is missing
- Make max_tokens configurable for aux vision calls
- Conversation compression desynchronizes session ID between agent context and gateway routing, causing silent message loss
- [Bug]: v0.15.0 Docker image:The TUI cannot be used in the dashboard.
- cron: skip_memory=True blocks fact_store/memory tools from all cron jobs
- TUI: Node.js OOM crash when agent uses browser tools repeatedly
- feat: model_profiles — per-model toolset and memory config
- Automatic background skill patching disrupts active sessions (severe impact on local models)
- ensure_hermes_home() creates root-owned dirs in profile subdirectories when kanban workers are dispatched
- Feature: opt-in webhook bypass for DISCORD_ALLOW_BOTS — allow operator-initiated probes without weakening bot-loop guard
- v0.15.0: Codex requests fail HTTP 400 when participant display_name contains non-ASCII (emoji breaks input[].name pattern)
- Architecture: State Persistence Precedence (Memory vs Skills vs Hooks)
- [Bug]: cronjob tool: create action always fails with "schedule is required for create" even when parameters are provided
- codex-oauth: 'NoneType' object is not iterable in _run_codex_stream (gpt-5.5) — every turn fails non-retryably
- Docs/Config: Plugin local scope enablement ambiguity
- [Bug]: CLI freezes after using /new command (WSL)
- Profile Codex auth can ignore global credential pool when local state is stale
- [workflow-engine] CRITICAL: variable substitution crashes on regex metachars in user input
- [workflow-engine] HIGH: loop and bash nodes leak subprocesses on timeout
- [workflow-engine] HIGH: README documents config env vars the engine never reads
- [workflow-engine] MEDIUM: workflow_run rate limit bypassable via concurrent calls (TOCTOU)
- [workflow-engine] chore: manifest gaps, side-effectful register(), dead code, unauth kanban dispatch
- [mcp_lazy] HIGH: synthetic mcp_server_<name> stub collides with a real MCP server named 'server'
- [mcp_lazy] HIGH: promote_server eager flag documented but never persisted
- [mcp_lazy] MEDIUM: _prev_mode dict leaks and goes stale; not cleared on session evict
- [mcp_lazy] MEDIUM: get_pool has unlocked check-then-set race on pool creation
- [mcp_lazy] MEDIUM: pre_tool_call gives no guidance for unpromoted server-stub calls
- [mcp_lazy] chore: undeclared pre_tool_call hook, nonexistent 'mcp_load_tools' name in docs, missing tests
- [a2a_fleet] CRITICAL: server never auto-starts — register() runs outside an event loop
- [a2a_fleet] CRITICAL: auth_required defaults to false on a cross-machine surface
- [a2a_fleet] HIGH: remove invented disable() hook — loader never calls it, port leaks on reload
- [a2a_fleet] HIGH: plugin.yaml missing kind / provides_tools / requires_env (token env undeclared)
- [a2a_fleet] MEDIUM: tighten wide-open CORS, anonymous /health peer leak, and peer-URL SSRF
- [a2a_fleet] MEDIUM: relocate tests to tests/plugins/ and cover sync-register + auth-default paths
- xai-oauth auxiliary client incorrectly uses Responses API (CodexAuxiliaryClient), causing 403 on compression/vision/web_extract
- [Bug]: Direct Copilot gpt-5.5 large resumes are killed by 12s Codex TTFB watchdog
- [Bug]: `hermes uninstall` does not work on Windows
- TUI: Thinking block leaks raw JSON and Σ character
- Hostinger VPS: migration Hermes Agent → Hermes WebUI impossible (tini + UID mismatch + sessions)
- /goal judge over-continues exploratory goals unless the assistant explicitly says the goal is complete
- /goal auto-continuation can be amplified by preflight compression/session split and resurrect stale task state
- Dashboard infinite reload loop in loopback mode — GET /api/auth/me returns 401 on every page load
- [Bug]: Provider/LLM switch leaves stale encrypted_content causing 400 errors on Telegram sessions
- [Bug]: Infinite reload loop / React state loop on Sessions tab (Firefox + Chrome) — repeated 401 on /api/auth/me (v0.15.0)
- show_reasoning should work independently of streaming in CLI mode
- Feature Request: Strip reasoning/<think> blocks from TTS preprocessing
- mcp add / mcp test raise NameError when mcp package not installed
- v0.14.0 dashboard breaks behind reverse proxies — two regressions
- Skills hub creates empty category directories when no skills installed
- [Bug]: Custom endpoint: ChatCompletions returns content, but Hermes treats response as empty (v0.14.0)
- fix: atomic_replace() fails with EXDEV when HERMES_HOME is a cross-filesystem symlink
- fix(gateway): Feishu session cancellation orphans session guard, permanently blocking messages
- Custom endpoint pricing can overestimate Crof qwen3.5-9b cost by 1,000,000x
- MCP OAuth callback: module-level port global causes port collisions and structural weaknesses vs upstream
- Bug: send_message tool bypasses validate_media_delivery_path security check
- Proposal: Add Mnemosyne to official memory provider documentation
- feat(swarm): support custom verifier/synthesizer body + skills
- Template conversion failed
- Error occurred in the operation of the agent node in the workflow.
- PubSub client overrides Sentinel client when REDIS_USE_SENTINEL is enabled
- Frontend description of the Retrieval node output does not match the actual output
- JSON type input var raise Intenal server error
- cannot extract elements from a scalar
- 负载均衡 为模型配置多组凭据,并自动调用,此功能无法选择
- add models is error
- panic: could not create filter
- Persist partially generated messages when /chat-messages/:task_id/stop is called
- MCP server connection fails with 403 — request never leaves Dify (SSRF proxy suspected)
- Support durable async execution backends for long-running workflow steps
- [Xiaomi MiMo] Credentials validation fails with 400 "Not supported model mimo-v2-flash" when using Token Plan endpoint (v0.0.7)
- After clicking preview on a parent-child segmented knowledge base, it shows 0 chunks
- Retrieval score differs between UI upload (.docx) and API upload (.txt) despite identical chunk content and embedding model
- gemini cli crash again
- Xbox gift card code damage
- Damage caused by the gemini cli crash
- ioctl(2) failed, EBADF (Bad File Descriptor)
- Feat: Support Bun as an alternative runtime/package manager for updates and extensions
- fatal error again!!!!
- ioctl error
- Critical Crash: ioctl(2) failed, EBADF in ShellExecutionService.resizePty
- ioctl(2) failed, EBADF
- v0.44.0 Regression: Critical crash with ioctl(2) failed, EBADF during PTY resize
- Crash on startup: ioctl(2) failed, EBADF in UnixTerminal.resize
- Crash: `ioctl(2) failed, EBADF` in `node-pty` during PTY resize on macOS
- Gemini CLI crashes with `ioctl(2) failed, EBADF` in `node-pty` during `resizePty`
- Remote Role
- ERROR ioctl(2) failed, EBADF /home/mich
- RangeError: Maximum call stack size exceeded
- EBADF Error during folder creationg broke session and terminal glitches
- MAIP / Gargoub Project - Mediterania - North Coast
- Gemini cli crash again in this morning
- ERROR ioctl(2) failed, EBADF
- Verified node install fails — Checksum verification failed (Cloud)
- The extended debugging key did not arrive during registration.
- CollaborationPane unmounts collaboration store on single-user instances, causing permanent "No network connection" state
- Workflow cannot be saved when the name contains "->" (Potentially malicious string)
- automation does not work and does not show an error
- Raj Ai Automation
- Default Data Loader: DOMMatrix is not defined error
- Feature: Per-node execution timestamp overlay on canvas during workflow run
- AI Agent + Vertex `gemini-3.5-flash`: 400 "missing thought_signature" on sequential multi-turn tool calls (post-#24982)
- PDF Loader in Pinecone Vector Store fails due to pdf-parse version conflict (v2 not supported)
- emailReadImap: add UID deduplication, batch size cap, and numeric uid enforcement
- Manual node execution fails with "Could not find a node" when autosave is disabled (N8N_WORKFLOWS_AUTOSAVE_DISABLED)
- Schedule Trigger stopped firing — workflow Published & active, manual executions succeed, no automated fires for 2+ hours
- [MCP SDK] create_workflow_from_code intermittently returns HTTP 500, often as a false negative (workflow persists anyway, causing duplicates on retry)
- Credential-load wedge: workflows using googleApi/jwtAuth credentials silently fail to execute after key rotation
- Google Sheets Trigger every minute is not working manual Execute is working sent email
- [BUG] Plugin marketplace MCP connector remains stuck "still connecting" when mcp-remote requires OAuth
- [redacted at user request]
- Opus 4.7 behavioral regression: loaded instruction-following discipline degraded in recent Claude Code/Cowork updates
- [BUG] Tailscale via Homebrew CLI + Mac App Store GUI, both Macs on macOS, Cowork blocked by VPN detector despite Tailscale being a mesh VPN with no traffic interception
- stopShellPty on tab switch kills active sessions (exit 143) — regression in May 27 build
- [BUG] Long URLs are broken into multiple lines and become unclickable in terminal output
- [BUG] claude rm/stop/reap SIGKILLs background session tree without SIGTERM grace, orphaning git index.lock and similar
- [BUG] Default git workflow in the system prompt was pushed without context or consent
- [MODEL] Inconsistent output quality / Ignoring instructions (overfitting and inappropriate repetition of Korean vocabulary)
- You've hit your weekly limit · resets May 31 at 5pm (Asia/Shanghai)
- Paid yearly subscription silently downgraded to Free with no user action
- [Regression v2.1.153] Plugin bash hooks fail with "echo: write error: Permission denied" on Windows (claude-mem, shell: "bash")
- [BUG] Connector toggles in conversation are not clickable — must click text label instead
- [remote-control] Input from mobile app/browser not reaching host session — output works fine
- Model fails to read/reference CLAUDE.md contents despite being loaded in context
- [BUG] Claude Desktop reinstall destroys Code chat history (transcripts + Recents) while regular Chat history, project files, and memory all survive
- Bypass mode clamps to Accept Edits even with the toggle ON (Claude Code Desktop 1.9255.2 / CC 2.1.149)
- [BUG] TUI input freezes randomly mid-typing — entire prompt becomes unresponsive for minutes
- [BUG] Cowork downloads Linux ELF binary instead of macOS binary on macOS Sonoma 14.8.7 — exit code 132 (SIGILL) on every session
- [Feature Request] Persistent project memory — sessions forget everything on close, forcing users to keep many sessions open
- [Bug] Thread context stale after sleep/resume, returns outdated date and calendar data
- [FEATURE] Add context window usage indicator and warning before auto-compaction
- [BUG] Dictation error: Invalid character in header content ["x-config-keyterms"] on Windows
- [Bug] Anthropic API Error: Server rate limiting despite normal usage
- Does delegating work to `claude -p` subprocesses reduce context accumulation in the parent session?
- [BUG] Claude Code hangs on M1 Mac when terminal says "opening browser to sign in" and browser opens
- [BUG] Claude_Preview MCP preview_start spawns dev server with main-repo cwd instead of session's worktree cwd
- [Bug] Anthropic API Error: Server rate limiting during request execution
- [Bug] Anthropic API Error: Server rate limiting on concurrent requests
- [Bug] Ultraplan ready notification fires before cloud agent completes execution
- [BUG] API 500 ERROR ALL THROUGHOUT THE DAY
- [BUG] Cowork: Live Artifacts folder path changed in 1.9255.2, no automatic migration from Documents\Claude\Artifacts
- [Bug] Auto-compact never triggers despite statusline reporting "100% context used" (v2.1.153, Max sub, 200K mode)
- [BUG] [Desktop / macOS] 'Open in → New Window' detached session: font renders smaller than main, no per-window controls, Cmd+/Cmd- keystrokes routed to main window instead
- Feature request: option to switch between classic and new minimal UI
- [Feature Request] Show timestamps for each message
- [BUG] Terminal corruption when permission prompt appears while navigating Agent Teams agent selection menu
- [FEATURE] Allow users to customize the background color of the Claude desktop app beyond the current light/dark theme presets.
- [BUG] Statusline not displaying on Windows [fixed]
- Background agent UI Stop button is a no-op for stuck agents — process keeps consuming tokens
- Background agents silently die on session pause/resume — no completion notification, no work recovery
- Add option to hide email address from welcome banner
- [BUG] SSH Remote: `projects` field in remote ~/.claude.json becomes null after desktop restart — jsonl files intact, UI shows 'No messages yet' for every session
- [Bug] Claude Code not applying fixes despite claiming to complete tasks
- billing is unfair and poorly documented
- [BUG] Claude Code on the web: declared plugins inactive on first session, require restart to fully load
- [BUG] Restore from archive deleted sessions instead of restoring them
- [BUG] M365 connector fails with AADSTS50011 in Cowork — localhost vs 127.0.0.1 redirect URI mismatch
- claude agents: workflow slash-commands missing from dispatch-input completion (regression-adjacent to #61424)
- Claude Desktop's Info.plist missing TCC usage strings, blocks all EventKit-based MCP servers
- False-positive safety blocks on self-administered governance amendments — request for owner-authority mode for verified professional users
- [BUG] Stop pushing "AUTO"-mode
- [DOCS] Plugin marketplace guide omits `skipLfs` option for git-based sources
- [DOCS] MCP docs omit combined startup notification for MCP server and connector authentication
- [DOCS] Agent view docs omit macOS Privacy & Security identity for background agents
- [DOCS] Npm update docs do not explain release-channel behavior for `claude update`
- [DOCS] Agent SDK docs omit `subagent_type: "claude"` worktree and output persistence behavior
- [DOCS] Background session docs omit `$CLAUDE_JOB_DIR` temp-file behavior
- [FR] mask env-var values in 'claude mcp get <server>' output
- [FR] subagent worktrees should not inherit stale local 'user.email' from prior dispatches
- [BUG] Windows: Grep tool leaks rg.exe + conhost.exe processes (~2000 zombies / 14 GB RAM in long sessions)
- [BUG] Stats dashboard "Peak hour" appears off by one hour
- [BUG] Diff highlight (teal SGR background) bleeds past changed text in 2.1.150–2.1.153
- [FEATURE] confirm before deleting session
- Plugin PostToolUse hooks still silently skip in Claude Desktop / Cowork (re-filing closed #51904)
- /code-review skill: silent fallback to main...HEAD reviews other people's commits, and JSON-only output is hard to read
- Monitor tool doesn't source the shell snapshot like Bash does; PATH-dependent tools (jq, sleep, etc.) fail in Monitor commands on macOS/Nix
- [Bug] Long input lines truncated with ellipsis while typing instead of wrapping in terminal UI
- [FEATURE] VS Code extension: Render submitted user messages as Markdown in chat
- OSC 52 copy from Claude TUI doesn't reach clipboard inside tmux (regression in 2.1.146–2.1.153)
- [BUG] RemoteTrigger create/update returns HTTP 400 with circular error: "event_type is required" / "unknown field event_type"
- [BUG] Option to hide or minimize the built-in "status footer" (multi-line debug/cost panel) [re-raise of #31475]
- [Bug] Feedback submissions being closed without review or action
- [FEATURE] Word-jump cursor navigation in Chat input (option+arrow / bindable actions)
- [FEATURE] ! shell mode: filesystem tab completion
- [BUG] API Error: Usage credits required for 1M context
- claude agents: OSC 52 clipboard emission broken in tmux (regression in 2.1.146–2.1.153)
- CLI crashes on macOS 15 M3 - exit code 1
- [FEATURE] Support Cmd+V image paste from clipboard
- [FEATURE] Enhance claude.ai M365 connector to support MS Planner
- [BUG] Slash command autocomplete hijacks pasted absolute file paths starting with /
- PreToolUse hook `if` filter false-positives on complex Bash commands
- [BUG] Diff panel hangs/whites out
- Feature Request: Support drag-and-drop for binary documents (.wps, .doc, .docx, .xlsx, .pdf) in VS Code extension
- [BUG] activation of 1M context in VSCode
- [FEATURE] Support i18n / language localization for built-in slash command outputs
- Ctrl+V para colar imagens deixou de funcionar no CLI (Windows, PowerShell)
- [FEATURE] Please add Norwegian (Bokmål/Nynorsk) language support to the Claude Code interface
- [BUG] OTel log events (claude_code.user_prompt, api_request_body, tool_decision, hook_execution_complete) emitted with empty trace_id/span_id while sibling spans correlate correctly
- [BUG] Cowork crashes on every message, no VM logs generated, missing AppData\Roaming\Claude
- [FEATURE] first-class session handoff + per-session token budgets for unattended runs
- [FEATURE] Smart paste: convert clipboard code to file reference chips (like Cursor)
- [Feature Request] Restore chat pin functionality to title chat submenu
- [BUG] SIGILL issues with version 2.1.153
- [BUG] Cowork plugin upload fails with generic "Plugin validation failed" when a `description` field in any SKILL.md frontmatter contains angle brackets (`<…>`)
- [BUG] Desktop App 2.1.144+: startup scanner deletes cliSessionId from claude-code-sessions local files on every launch — session not found on disk
- [Feature Request] Add keyboard shortcut to copy last message with proper formatting
- [MODEL] Opus 4.7 not 1M
- Allow naming/renaming background agents in `claude agents` view
- Stale worktrees in .claude/worktrees/ are never cleaned up, consuming massive disk space
- Agent worktrees are never cleaned up, silently consuming disk space
- Subagent worktrees not auto-cleaned when reviewer writes scratch files
- [Bug] Skill initialization hangs for extended duration in Plan Mode
- Claude Desktop writes malformed registry Run entry (nested escaped quotes) - crashes Windows Task Manager and other Run-key parsers
- IME candidate window shows at bottom-right corner instead of caret position (Windows CMD)
- [BUG] Pressing 'Escape' doesn't close the /BTW conversation when the main conversation is asking for approval
- [BUG] Opus 4.7 (1M) intermittently emits empty-string values for tool_use.input fields, killing the session
- FleetView agent UI shows "running" with incrementing elapsed time after agent has returned
- /doctor flags context-scoped cmd+c binding as macOS conflict (false positive)
- [BUG] Text Rendering in Elvish
- Desktop app: Bypass Permissions mode flips to Accept Edits on first prompt (M5 / macOS 26.5)
- [Workaround] Date-Weekday Verification Hook — Prevents Claude from writing wrong weekdays
- [BUG] Claude Code create c:/memfs directory without asking me.
- [BUG] Claude Code's Bash execution waits forever with no processes running
- [BUG] usage stays stuck waiting for 5 hr limit after upgrading to premium seat in team plan
- [Workflow tool] resume cache is unreachable for nontrivial workflows because LLM dispatchers can't transcribe args byte-exactly
- Code review (Preview): "Add a repository" shows no results for private GitHub org repos
- [BUG] /context commands blows up context
- [Feature Request] Add precache expiry hook to enable proactive compaction before token eviction
- [BUG] Context indicator shows 0% at session start despite ~20K+ tokens already loaded
- [Feature Request] Add semantic search for --resume session history
- [Feature Request] Add session search, tagging, and filtering capabilities
- [BUG] Cowork Dispatch reports "desktop not available" on Windows 11 while standard Cowork works normally
- [Bug] Claude Code provides incorrect suggestions with high confidence despite errors
- defaultMode: acceptEdits silently overrides per-path permissions.ask rules for Write/Edit
- [FEATUR configurable tip interval (e.g. tipIntervalSeconds: 30 in settings)E]
- Plugin marketplace fails to load: schema rejects 'displayName' key (v2.1.153)
- claude agents: in-session copy uses broken OSC 52 path while overview correctly uses tmux buffer
- [BUG] Plugin agent descriptions (and custom agents) load unconditionally into context — no parity with disable-model-invocation for skills
- Crashed ultrareview consumed a free credit despite producing zero findings
- [Bug] Character rendering issue - invisible or missing text display
- [BUG] Cowork: processo Claude Code encerra com código 3 — .claude.json não contém token de autenticação (Windows 11 25H2)
- [BUG] 2.1.153 silently discards tools/list response from rmcp 0.12.0 HTTP MCP server (works in 2.1.152, wire-identical handshake)
- VS Code extension: option to auto-resume last session when reopening a workspace folder
- [Bug] Conversation continuation failure
- [BUG] Cowork crashes every time I start a new chat or attempt to continue an existing one in any project. The error displayed is: "Claude Code è andato in crash
- [Bug] Unannounced quota changes
- Native update/install fails with 'socket connection was closed unexpectedly' behind proxy — undici TLS incompatibility
- [BUG] Session name reverting after manual change
- [BUG] 非正常思考,上下文过长时,一直显示思考,点击interrupt按钮失效
- Honor `tools:` frontmatter when an agent is invoked via `@mention` — strip `Task` only when the agent did not declare it
- macOS TCC popup still recurring on v2.1.153 — "2.1.153" would like to access data from other apps
- Claude Code leaks pty handles — exhausts pseudo-terminals on macOS after long session
- [Bug] Agent fails to execute or respond to user input
- [BUG] Persistent "Expecting value: line 1 column 1 (char 0)" JSON parse error after tool execution
- [Feature Request] Implement proactive unit test coverage recommendations for recurring bugs
- VS Code panel lacks status line + terminal lacks image paste in Codespaces, forcing a tradeoff
- `/powerup` only shows ~10 lessons — allow viewing the full catalog
- [Bug] Context contamination after auto-compact with unrelated email draft of Tejo/Sado Basin
- [Bug] VSCode terminal output displays corrupted text with garbled symbols
- [Feature Request] Add LaTeX/KaTeX math rendering to TUI
- [Bug] Sub-agent PR review results not validated by orchestrating agent
- Subagents on Pro 1M tier: trivial probes pass, real workloads fail at first tool call (probe-vs-workload divergence)
- Path-scoped rules and subdirectory CLAUDE.md not loaded when creating new files matching the pattern
- AskUserQuestion: cancelling during extended thinking poisons the whole session with 400 'thinking blocks cannot be modified' (2.1.153); concurrent prompts overwrite each other
- Ideas Missing from Claude Cowork Menu (Windows)
- [BUG_BOUNTY_SAFE_POC_2026] Prompt Injection RCE Test - Command Execution Proof
- [BUG] Cowork scheduled task: execution history row not showing after successful run
- Resuming an extended-thinking session fails permanently with 400 "thinking blocks cannot be modified" (transcript stores thinking text as empty but keeps signature)
- [Bug] Plugin-registered CwdChanged and FileChanged hooks don't fire (settings.json works) — v2.1.153
- Auto-archive on PR merge / branch delete — clarify autoArchiveSessions semantics or add dedicated opt-out
- `claude mcp add` echoes Authorization header value verbatim to stdout, leaks bearer tokens to terminal and session transcripts
- [BUG] Bug report — /insights skill, Claude Code The /insights skill outputs a malformed file path.
- Plugin slash commands render with '*'-inline format instead of two-column, despite matching official plugin shape
- [Bug] Unexpected long text generation without user input or goal
- [Bug] Thinking blocks causing task progression blocked without user modification
- [BUG] (Critical!) contamination by an unknown session simirlar to the report => [Bug] Context contamination after auto-compact with unrelated email draft of Tejo/Sado Basin #63137
- [Critical] Opus 4.7 Korean output degeneration — Korean grammar itself collapses in long contexts
- [BUG] Title: Autocompact buffer persists across /clear — wastes tokens for irrelevant old context
- [Bug] Auto-Compact loses user input before processing in conversation history
- Feature: per-invocation effort parameter + runtime session-config introspection for skills
- Auto-mode classifier mislabels Azure DevOps vote -5 as "Reject" when denying PR vote actions
- [BUG] Claude Desktop and Claude Code CLI never re-register MCP tools after OAuth 2.1 handshake on a remote HTTP server
- [BUG] Workspace file tags leak across sessions
- [BUG] Ink renderer crashes on Windows 11 build 26200 (Canary) duplicate banners, terminal mode leaks, mid-operation aborts
- [BUG] Claude Code Desktop issue
- PTY master fd leak in Claude desktop app exhausts macOS kern.tty.ptmx_max after ~2-3 days
- [BUG] Claude Code — Session Management after Unexpected Interruption
- [Windows] Cowork OpenTelemetry exporter does not initialize - zero events emitted to any destination, including loopback
- [Bug] Opus 4.7: 400 `thinking blocks ... cannot be modified` on long extended-thinking sessions, triggered by history-altering events (scheduled prompts / parallel tool-call cancellation)
- [BUG] API Error: Server is temporarily limiting requests (not your usage limit) · Rate limited
- Multi-plugin custom marketplace: only first plugin registered in installed_plugins.json, skills don't load
- [BUG] Git push through the SDK's git proxy fan-outs into ~500 GitHub REST API calls, exhausting the 5,000/hour budget after a handful of pushes
- [BUG] Claude took liberties it really shouldn't with my global config
- [BUG] Agent window focus lost after navigating with arrow keys, causing scroll deadlock
- [BUG] `--model` flag silently ignored in interactive sessions (works in `--print` only)
- [BUG] Dispatch permanently shows "desktop appears offline" on Windows 11 - never worked on first use
- feat: support per-command enableWeakerNetworkIsolation as safer alternative to dangerouslyDisableSandbox
- /code-review outputs a raw JSON array instead of readable findings
- [BUG] Cowork — Additional allowed domains ignored on Team plan; same domain works on Pro plan
- Haiku
- [Bug] False positive blocking beneficial outcomes in tool execution
- 3P Bedrock SSO: credentials silently expire without triggering re-auth on day 2+
- CLAUDE_AUTOCOMPACT_PCT_OVERRIDE in settings.json env block silently ignored by autocompact logic
- Auto-compaction deletes main session JSONL before verifying summary completion, causing data loss
- [Bug] Claude Code not executing stated actions or producing expected results
- [FEATURE] Deferred Messages — Queue Input for End of Turn
- [BUG] Up/Down arrows in input box navigate history instead of moving cursor — regression in 2.1.149+
- Cancelling a parallel tool-call batch corrupts thinking blocks -> 400 "thinking blocks cannot be modified" permanently wedges the session
- Claude Code caused data loss, then contradicted itself about recovery (two incidents, one session)
- [Bug] Unclear error messages from Claude Code CLI
- [Bug] Agent tool rejecting due to context size limit exceeded
- claude agents: daemon and bg-spare processes spin at ~100% CPU when idle
- [BUG] Compaction fails with "context window limit" error even when context usage is low (e.g., 20%) — regression in v2.1.153
- Remote Control entitlement lost after May 27-28 incident — `Error: Remote Control is not yet enabled for your account` on active Max subscription
- PreToolUse hook exit code 2 does not block Write tool
- [Bug] Thinking blocks in latest assistant message are immutable
- GUI: dispatch file:// and custom-scheme clicks to OS shell handler
- Show current model in statusLine by default
- [Bug] Agent console becomes unresponsive to keyboard input after multiple agents initialized
- [FEATURE] PreToolUse hooks should have a way of updating the environment
- [Bug] Unable to start or use Claude Code CLI
- [BUG] Repository not visible in Claude Code web repo picker
- Session permanently wedged on 400 "thinking blocks cannot be modified" after parallel tool_results
- [Bug] @ autocomplete loses sibling repos after a file edit in multi-repo workspace
- Unclear error message when creating sub-agent without authentication
- [Bug] Anthropic API errors causing frequent failures and high token usage
- [BUG] @ mention file picker only shows packages, not individual files (desktop app - Code tab)
- [Bug] TUI panel footer remains sticky and consumes excessive terminal space
- PR-status polling exhausts GitHub GraphQL rate limit on repos with many open PRs
- [BUG] Windows: welcome panel not shown in some project folders (2.1.153)
- [Bug] Anthropic API Error: thinking blocks corrupted during context compaction with extended thinking enabled
- API 400 "thinking blocks cannot be modified" permanently bricks session during agent activation (interleaved thinking + tool use)
- Right-click Copy copies the whole message instead of the selection; pasted text retains dark background
- Mid-session model switch corrupts conversation when extended thinking is enabled (API 400: 'thinking blocks cannot be modified')
- [BUG] Markdown file links in chat output do not open files when clicked (VS Code extension)
- Stuck retry loop: `400 thinking blocks cannot be modified` on large interleaved-thinking turns using AskUserQuestion
- [FEATURE] Prompt user for approval before auto-compaction proceeds
- Custom MCP connectors not attachable to scheduled routines — no UUID discovery path
- [BUG] Claude in Chrome — Navigation blocked for teams.cloud.microsoft and outlook.cloud.microsoft after Microsoft domain migration**
- [BUG] Claude Desktop — Personal plugins panel renders list but is entirely non-interactive (macOS, v1.9255.2)
- [Bug] error when using Workflows
- [BUG] Persistent "update available" notification despite being on latest version
- [BUG] Sweep Agent from /code-review never completes
- [Bug] Tool calls not executing or returning results
- [FEATURE] Cloud-synced memory and settings across machines
- [Bug] Terminal UI freezes when Ctrl+O view exits during interactive prompt in plan mode
- Continuous api errors when using claude code with Opus 4.7 with thinking on low
- [Feature Request] Add support for installing and using previous Claude Code versions
- [Bug] Extended Thinking: Summarized thinking blocks fail signature validation when resent to API
- [Bug] Anthropic API Error: 'thinking' blocks cannot be modified
- [Bug] Anthropic API Error: Thinking blocks cannot be modified with extended thinking mode
- Feature request: Lazy/on-demand MCP server connections
- [Bug] Tool Arguments Parsed as String Instead of Object
- [Bug] Anthropic API Error: Insufficient context provided
- [Bug] Claude Opus occasionally uses moskovian(russian) orthography instead of Ukrainian in system-prompted responses
- Opus 4.8: backgrounded task completions (subagents AND Bash) crash with 400 "thinking blocks cannot be modified"
- [Bug] Opus 4.7 fabricates stable preferences ("my default") to rationalize arbitrary choices when challenged
- [Bug] Unable to update Claude Code CLI
- [BUG] Desktop app: /remote-control mints link + connects bridge (main.log) but in-chat link/QR panel never renders
- Feature: sessionColor and sessionName in .claude/settings.json
- [BUG] Anthropic API error: thinking blocks
- [FEATURE] Support Remote MCPs in Cowork as in Claude Code
- [Bug] Anthropic API Error: 400 Bad Request with Redacted Thinking - 0 4.7 & 4.8
- [Bug] Anthropic API Error: Cannot modify thinking blocks from different model versions
- Interleaved thinking + multi-tool turn corrupts thinking block (text blanked, signature kept) → permanent 400 'blocks must remain as they were'
- [BUG] Mode/permission changes mid-tool-loop (effortLevel: xhigh) poisons entire session
- Session failure log: Opus 4.6 ignores its own rules for an entire session
- [BUG] "400 Guardrail was enabled" error when using Claude Opus 4.8 with AWS Bedrock
- [Feature Request] Add subagent approach selection option to avoid accidental feedback
- Persistent 400 'thinking blocks in the latest assistant message cannot be modified' — interleaved thinking persisted with empty text + signature bricks sessions
- [BUG] DesktopvsApp
- [BUG] Opus 4.7 cache hit rate collapse after May 27 incident — Messages 1.1k→88.9k in 9 minutes, $630/session
- [Bug] Anthropic API Error: Invalid thinking block format
- [BUG] FUCK CLAUDE
- Opus 4.8 extended thinking: Stop hook block re-entry corrupts thinking blocks → 400
- [Bug] 4.8 Fails when accessing previous model history
- [Bug] Unintended File Modifications During Execution
- [DOCS] Model configuration docs omit lean system prompt default scope and model exceptions
- Add "Always allow globally" option to permission prompts
- Server-side model upgrade (Opus 4.7→4.8) wedges in-flight sessions with `thinking blocks cannot be modified` 400
- [DOCS] AskUserQuestion docs missing multiple-choice prompt decision threshold
- [DOCS] Agent view docs omit shell-command background session launch syntax
- [DOCS] Agent view dispatch input docs incorrectly imply `/logout` dispatches as a prompt
- [DOCS] Claude in Chrome docs omit connected-browser selection behavior
- [DOCS] Plugin docs omit `defaultEnabled: false` for opt-in plugins
- Feature Request: Customizable chat text colors for user and assistant messages
- [DOCS] `/plugin` Discover tab docs omit directory-based suggested plugin pins
- VSCode Chrome integration silently fails: 3 distinct bugs
- [DOCS] MCP stdio docs omit session environment variables
- [Bug] Anthropic API error on second request within session with Claude Opus 4.8
- Cowork emits a blank session "index" handoff on focus when a CLI session is paused awaiting input
- [DOCS] MCP docs omit `claude mcp list/get` pending-approval output for unapproved project servers
- [BUG] /compact fails with 400 error when last assistant turn contains thinking blocks
- [DOCS] `/claude-api` docs omit Opus 4.8 migration guidance
- [DOCS] Fast mode docs still recommend deprecated Opus 4.6 override variable
- [DOCS] Bash tool docs omit `$TMPDIR` consistency across sandboxed and unsandboxed commands
- [Bug] Anthropic API Error: 400 Bad Request on Extended Thinking
- [DOCS] Background session docs omit worktree-isolation behavior for spawned subagents
- Built-in mechanistic self-verification of verifiable claims (symmetric to the auto permission gate)
- [DOCS] Worktree docs do not clarify `worktree.baseRef: "head"` inside linked worktrees
- [BUG] Excessive RAM usage with multiple parallel chats (~10 sessions → 30 GB memory pressure, macOS OOM)
- [DOCS] Managed MCP policy docs omit invalid `allowedMcpServers`/`deniedMcpServers` entry behavior
- [DOCS] Effort docs omit `CLAUDE_CODE_ALWAYS_ENABLE_EFFORT` unsupported-model behavior
- Regression (2.1.147–2.1.150?): resuming an extended-thinking session after a CC update/model-switch → unrecoverable 400, session bricked
- [DOCS] Windows updater docs omit `claude.exe` in-use recovery guidance
- [DOCS] VS Code auto mode docs still tie mode-picker visibility to bypass-permissions setting
- [DOCS] MCP docs omit `/mcp` tool list and detail rendering behavior
- [DOCS] Fine-grained tool streaming docs still describe provider opt-in behavior
- bypassPermissions: session startup reads flat pref, GUI toggle writes per-account pref — they never sync
- [BUG] Claude Desktop Code tab causes disk write limit violation — 8.5GB in 11 min, macOS kills app (M5, v1.9659.1)
- Ultrareview v2.1.96: docs describe /tasks command + claude ultrareview --json subcommand that don't exist; findings hard to read after completion
- I'd be happy to help create a GitHub issue title, but I don't see the error message in your message. Could you please share the specific error you're encountering? That way I can generate an accurate and descriptive issue title for you.
- [BUG] Claude in Chrome `file_upload` rejects all scheduled-task sessions with misleading error (real cause: INVALID_SESSION)
- Extended thinking: signed thinking block 'cannot be modified' (400) permanently wedges session
- RTL text support for Hebrew (and Arabic) in Claude Code
- [Bug] Random errors occurring across multiple operations