From 198995c50a3f3fa4ccd8db54efcaa130a5fc469b Mon Sep 17 00:00:00 2001 From: Duc Nguyen Date: Mon, 6 Apr 2026 13:18:01 +0700 Subject: [PATCH 1/4] docs(whatsapp): rewrite WhatsApp channel docs for Baileys bridge implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace placeholder whatsapp-web.js docs with actual Baileys bridge setup - Add QR code authentication flow, media support, typing indicators - Document bridge protocol (Bridge↔GoClaw JSON messages) - Add Docker Compose quick start and manual setup instructions - Add config reference with correct defaults (pairing, not open) - Add formatting table (Markdown→WhatsApp native conversion) - Add troubleshooting for common issues (#703: format mismatch) - Update INDEX.md comparison tables (media, auth method, complexity) - Update setup checklists across all 3 locales (en, vi, zh) --- channels/INDEX.md | 20 ++-- channels/whatsapp.md | 239 ++++++++++++++++++++++++++------------- vi/channels/INDEX.md | 12 +- vi/channels/whatsapp.md | 243 +++++++++++++++++++++++++++------------- zh/channels/INDEX.md | 20 ++-- zh/channels/whatsapp.md | 243 +++++++++++++++++++++++++++------------- 6 files changed, 518 insertions(+), 259 deletions(-) diff --git a/channels/INDEX.md b/channels/INDEX.md index c2c68ad..3f6b004 100644 --- a/channels/INDEX.md +++ b/channels/INDEX.md @@ -11,7 +11,7 @@ Complete documentation for all messaging platform integrations in GoClaw. 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook, streaming cards, media 6. **[Zalo OA](./zalo-oa.md)** — Official Account, DM-only, pairing, images 7. **[Zalo Personal](./zalo-personal.md)** — Personal account (unofficial), DM + groups -8. **[WhatsApp](./whatsapp.md)** — External bridge, JSON protocol, auto-reconnect +8. **[WhatsApp](./whatsapp.md)** — Baileys bridge, QR auth, media, typing indicators, pairing 9. **[WebSocket](./websocket.md)** — Direct RPC, custom clients, streaming events 10. **[Browser Pairing](./browser-pairing.md)** — 8-char code auth, session tokens @@ -19,15 +19,15 @@ Complete documentation for all messaging platform integrations in GoClaw. | Feature | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo Pers | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| -| **Setup Complexity** | Easy | Easy | Easy | Medium | Medium | Hard | Hard | Very Easy | -| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Bridge | WebSocket | +| **Setup Complexity** | Easy | Easy | Easy | Medium | Medium | Hard | Medium | Very Easy | +| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Baileys Bridge | WebSocket | | **DM Support** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | N/A | | **Group Support** | Yes | Yes | Yes | Yes | No | Yes | Yes | N/A | | **Streaming** | Yes | Yes | Yes | Yes | No | No | No | Yes | -| **Rich Format** | HTML | Markdown | mrkdwn | Cards | Plain | Plain | JSON | JSON | +| **Rich Format** | HTML | Markdown | mrkdwn | Cards | Plain | Plain | WA native | JSON | | **Reactions** | Yes | -- | Yes | Yes | -- | -- | -- | -- | -| **Media** | Photos, Voice, Files | Files, Embeds | Files (20MB) | Images, Files | Images | -- | JSON | N/A | -| **Auth Method** | Token | Token | 3 Tokens | App ID + Secret | API Key | Credentials | Bridge | Token + Pairing | +| **Media** | Photos, Voice, Files | Files, Embeds | Files (20MB) | Images, Files | Images | -- | Images, Video, Audio, Docs | N/A | +| **Auth Method** | Token | Token | 3 Tokens | App ID + Secret | API Key | Credentials | QR Code | Token + Pairing | | **Risk Level** | Low | Low | Low | Low | Low | High | Medium | Low | ## Configuration Files @@ -142,9 +142,11 @@ Flexible format supporting: ### WhatsApp -- [ ] Deploy WhatsApp bridge service (e.g., whatsapp-web.js) -- [ ] Copy WebSocket URL -- [ ] Enable in config +- [ ] Deploy bridge: `docker compose -f docker-compose.whatsapp.yml up -d` (or `cd bridge/whatsapp && npm install && node server.js`) +- [ ] Create channel in UI: Channels > Add Channel > WhatsApp +- [ ] Set Bridge URL (e.g., `ws://whatsapp-bridge:3001`) +- [ ] Scan QR code with WhatsApp (You > Linked Devices > Link a Device) +- [ ] Configure DM/group policies as needed ### WebSocket diff --git a/channels/whatsapp.md b/channels/whatsapp.md index ad76757..25677fa 100644 --- a/channels/whatsapp.md +++ b/channels/whatsapp.md @@ -1,26 +1,47 @@ # WhatsApp Channel -WhatsApp integration via external WebSocket bridge. GoClaw connects to a bridge service (e.g., whatsapp-web.js) that handles the WhatsApp protocol. +WhatsApp integration via an external Baileys-based WebSocket bridge. GoClaw connects as a WS client to the bridge, which handles the WhatsApp multi-device protocol (no Chrome required). ## Setup -**Prerequisites:** -- Running WhatsApp bridge service (e.g., whatsapp-web.js) -- Bridge URL accessible to GoClaw +### Quick Start (Docker Compose) -**Start WhatsApp Bridge:** +The fastest way to run WhatsApp is with the included Docker Compose overlay: -Example using whatsapp-web.js: +```bash +docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.whatsapp.yml up -d +``` + +Then in the GoClaw UI: +1. **Channels > Add Channel > WhatsApp** +2. Set **Bridge URL** to `ws://whatsapp-bridge:3001` +3. Choose an agent, click **Create & Scan QR** +4. Scan the QR code with WhatsApp (You > Linked Devices > Link a Device) + +### Manual Bridge Setup + +If you prefer running the bridge outside Docker: ```bash -npm install -g whatsapp-web.js -# Start bridge server on localhost:3001 -whatsapp-bridge --port 3001 +cd bridge/whatsapp +npm install +node server.js ``` -Your bridge should expose a WebSocket endpoint (e.g., `ws://localhost:3001`). +Environment variables: + +| Variable | Default | Description | +|----------|---------|-------------| +| `BRIDGE_PORT` | `3001` | WebSocket server port | +| `AUTH_DIR` | `./auth_info` | Directory for WhatsApp auth state | +| `MEDIA_DIR` | OS temp dir | Directory for downloaded media files | +| `MEDIA_MAX_BYTES` | `20971520` (20 MB) | Max media download size | +| `LOG_LEVEL` | `silent` | Bridge log level (`silent`, `warn`) | +| `PRINT_QR` | `false` | Print QR code to terminal (useful without UI) | -**Enable WhatsApp:** +### Config File Setup + +For config-file-based channels (instead of DB instances): ```json { @@ -28,9 +49,8 @@ Your bridge should expose a WebSocket endpoint (e.g., `ws://localhost:3001`). "whatsapp": { "enabled": true, "bridge_url": "ws://localhost:3001", - "dm_policy": "open", - "group_policy": "open", - "allow_from": [] + "dm_policy": "pairing", + "group_policy": "pairing" } } } @@ -38,104 +58,169 @@ Your bridge should expose a WebSocket endpoint (e.g., `ws://localhost:3001`). ## Configuration -All config keys are in `channels.whatsapp`: +All config keys are in `channels.whatsapp` (config file) or the instance config JSON (DB): | Key | Type | Default | Description | |-----|------|---------|-------------| -| `enabled` | bool | false | Enable/disable channel | +| `enabled` | bool | `false` | Enable/disable channel | | `bridge_url` | string | required | WebSocket URL to bridge (e.g., `ws://bridge:3001`) | | `allow_from` | list | -- | User/group ID allowlist | -| `dm_policy` | string | `"open"` | `open`, `allowlist`, `pairing`, `disabled` | -| `group_policy` | string | `"open"` | `open`, `allowlist`, `disabled` | +| `dm_policy` | string | `"pairing"` | `pairing`, `open`, `allowlist`, `disabled` | +| `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | `pairing`, `open`, `allowlist`, `disabled` | +| `require_mention` | bool | `false` | Only respond in groups when bot is @mentioned | | `block_reply` | bool | -- | Override gateway block_reply (nil=inherit) | -## Features - -### Bridge Connection - -GoClaw connects to the bridge via WebSocket and sends/receives JSON messages. +## Architecture ```mermaid flowchart LR - GC["GoClaw"] - WS["WebSocket
Connection"] - BRIDGE["WhatsApp
Bridge"] WA["WhatsApp
Servers"] + BRIDGE["Baileys Bridge
(Node.js WS Server)"] + GC["GoClaw
(WS Client)"] + UI["Web UI
(QR Wizard)"] - GC -->|"JSON messages"| WS - WS -->|"JSON messages"| BRIDGE - BRIDGE -->|"WhatsApp protocol"| WA - WA -->|"Protocol"| BRIDGE - BRIDGE -->|"JSON events"| WS - WS -->|"Events"| GC + WA <-->|"Multi-device protocol"| BRIDGE + BRIDGE <-->|"JSON over WebSocket"| GC + GC -->|"QR events via WS bus"| UI ``` -### DM and Group Support +- **Bridge** is the WebSocket **server** (default port 3001) +- **GoClaw** connects as a **client** and handles routing, AI, pairing +- One bridge instance = one WhatsApp phone number +- Media files are exchanged via a shared volume (`/tmp/goclaw_wa_media`) -Bridge detects group chats via `@g.us` suffix in chat ID: +## Features -- **DM**: `"1234567890@c.us"` -- **Group**: `"123-456@g.us"` +### QR Code Authentication -Policies apply accordingly (DM policy for DMs, group policy for groups). +WhatsApp requires QR code scanning to link a device. The flow: -In group chats, messages include a `[From:]` annotation with the sender's display name, allowing the agent to distinguish between participants. +1. Bridge generates QR via Baileys connection +2. Bridge sends `{type: "qr", data: ""}` to GoClaw +3. GoClaw encodes as PNG and broadcasts via bus event +4. Web UI wizard displays the QR image +5. User scans with WhatsApp (You > Linked Devices > Link a Device) +6. Bridge confirms auth: `{type: "status", connected: true}` -### Message Format +**Re-authentication**: Use the "Re-authenticate" button in the channels table to force a new QR scan (logs out the current WhatsApp session). -Messages are JSON objects: +### DM and Group Policies -```json -{ - "from": "1234567890@c.us", - "body": "Hello!", - "type": "chat", - "id": "message_id_123" -} -``` +WhatsApp groups have chat IDs ending in `@g.us`: -Media is passed as array of file paths: +- **DM**: `"1234567890@s.whatsapp.net"` +- **Group**: `"120363012345@g.us"` -```json -{ - "from": "1234567890@c.us", - "body": "Photo", - "media": ["/tmp/photo.jpg"], - "type": "image" -} -``` +Available policies: -### Auto-Reconnect +| Policy | Behavior | +|--------|----------| +| `open` | Accept all messages | +| `pairing` | Require pairing code approval (default for DB instances) | +| `allowlist` | Only users in `allow_from` | +| `disabled` | Reject all messages | -If bridge connection drops: -- Exponential backoff: 1s → 30s max -- Continuous retry attempts -- Logs warn on reconnect failures +Group `pairing` policy: unpaired groups receive a pairing code reply. Approve via `goclaw pairing approve `. -## Common Patterns +### @Mention Gating -### Sending to a Chat +When `require_mention` is `true`, the bot only responds in group chats when explicitly @mentioned. Fails closed — if the bot's JID is unknown, messages are ignored. -```go -manager.SendToChannel(ctx, "whatsapp", "1234567890@c.us", "Hello!") -``` +### Media Support + +The bridge downloads incoming media (images, video, audio, documents, stickers) to a shared volume. GoClaw reads these files and passes them to the agent pipeline. + +Supported inbound media types: image, video, audio, document, sticker. + +Outbound media: GoClaw writes files to the shared volume and sends the path to the bridge for delivery. -### Checking if Chat is a Group +**Shared volume** (Docker): Both `goclaw` and `whatsapp-bridge` containers mount the same volume at `/tmp/goclaw_wa_media`. + +### Message Formatting + +LLM output is converted from Markdown to WhatsApp's native formatting: + +| Markdown | WhatsApp | Rendered | +|----------|----------|----------| +| `**bold**` | `*bold*` | **bold** | +| `_italic_` | `_italic_` | _italic_ | +| `~~strikethrough~~` | `~strikethrough~` | ~~strikethrough~~ | +| `` `inline code` `` | ` ```code``` ` | `code` | +| `# Header` | `*Header*` | **Header** | +| `[text](url)` | `text url` | text url | +| `- list item` | `* list item` | * list item | + +Fenced code blocks are preserved as ` ``` `. HTML tags from LLM output are pre-processed to Markdown equivalents before conversion. + +### Typing Indicators + +GoClaw shows "typing..." in WhatsApp while the agent processes a message. WhatsApp clears the indicator after ~10 seconds, so GoClaw refreshes every 8 seconds until the reply is sent. + +### Auto-Reconnect -```go -isGroup := strings.HasSuffix(chatID, "@g.us") +If the bridge connection drops: +- Exponential backoff: 1s > 2s > 4s > ... > 30s max +- Continuous retry until bridge is available +- Channel health status updated (degraded/healthy) + +## Bridge Protocol + +### Bridge > GoClaw + +| Type | Payload | Description | +|------|---------|-------------| +| `status` | `{connected: bool, me: "jid"}` | Auth state (sent on connect + change) | +| `qr` | `{data: "qr-string"}` | QR code for scanning | +| `message` | `{id, from, chat, content, from_name, is_group, mentioned_jids, media}` | Incoming message | +| `pong` | `{}` | Response to ping | + +### GoClaw > Bridge + +| Type | Payload | Description | +|------|---------|-------------| +| `message` | `{to: "jid", content: "text"}` | Send outbound text | +| `command` | `{action: "reauth"}` | Logout + restart QR flow | +| `command` | `{action: "ping"}` | Health check | +| `command` | `{action: "presence", to, state}` | Presence (composing/paused) | + +## Docker Compose + +The `docker-compose.whatsapp.yml` overlay adds the bridge service: + +```yaml +services: + whatsapp-bridge: + build: ./bridge/whatsapp + ports: + - "3001:3001" + volumes: + - wa_auth:/app/auth_info # Persistent auth state + - wa_media:/tmp/goclaw_wa_media # Shared media volume + environment: + - BRIDGE_PORT=3001 + - PRINT_QR=false + + goclaw: + volumes: + - wa_media:/tmp/goclaw_wa_media # Same media volume + +volumes: + wa_auth: + wa_media: ``` ## Troubleshooting | Issue | Solution | |-------|----------| -| "Connection refused" | Verify bridge is running. Check `bridge_url` is correct and accessible. | -| "WebSocket: close normal closure" | Bridge shut down gracefully. Restart bridge service. | -| Continuous reconnect attempts | Bridge is down or unreachable. Check bridge logs. | -| Messages not received | Verify bridge is receiving WhatsApp events. Check bridge logs. | -| Group detection fails | Ensure chat ID ends with `@g.us` for groups, `@c.us` for DMs. | -| Media not sent | Ensure file paths are accessible to bridge. Check bridge supports media. | +| "Connection refused" | Verify bridge is running and `bridge_url` is correct. For Docker, use `ws://whatsapp-bridge:3001`. | +| No QR code appears | Check bridge logs. Ensure the bridge can reach WhatsApp servers. Try `PRINT_QR=true` for terminal QR. | +| QR scanned but no auth | Auth state may be corrupted. Delete `auth_info/` directory and restart bridge. | +| Messages not received | Check bridge protocol: must send `type:"message"` with `from`/`content` fields (not `sender`/`body`). | +| Media not received | Ensure shared volume is mounted in both containers. Check `MEDIA_MAX_BYTES` limit. | +| "Bridge format mismatch" warning | Your bridge sends messages without a `type` field. Add `type:"message"` and use `from`/`content` field names. | +| Typing indicator stuck | GoClaw auto-cancels typing when reply is sent. If stuck, the bridge connection may have dropped. | +| Group messages ignored | Check `group_policy`. If `pairing`, the group needs approval. If `require_mention` is true, @mention the bot. | ## What's Next @@ -144,4 +229,4 @@ isGroup := strings.HasSuffix(chatID, "@g.us") - [Larksuite](/channel-feishu) — Larksuite integration - [Browser Pairing](/channel-browser-pairing) — Pairing flow - + diff --git a/vi/channels/INDEX.md b/vi/channels/INDEX.md index 704f988..feb94bb 100644 --- a/vi/channels/INDEX.md +++ b/vi/channels/INDEX.md @@ -11,7 +11,7 @@ Tài liệu đầy đủ cho tất cả các tích hợp nền tảng nhắn tin 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook, streaming cards, media 6. **[Zalo OA](./zalo-oa.md)** — Official Account, chỉ DM, pairing, hình ảnh 7. **[Zalo Cá nhân](./zalo-personal.md)** — Tài khoản cá nhân (không chính thức), DM + nhóm -8. **[WhatsApp](./whatsapp.md)** — External bridge, giao thức JSON, tự động kết nối lại +8. **[WhatsApp](./whatsapp.md)** — Baileys bridge, xác thực QR, media, typing indicators, pairing 9. **[WebSocket](./websocket.md)** — RPC trực tiếp, custom client, streaming events 10. **[Ghép nối trình duyệt](./browser-pairing.md)** — Xác thực mã 8 ký tự, session token @@ -19,14 +19,14 @@ Tài liệu đầy đủ cho tất cả các tích hợp nền tảng nhắn tin | Tính năng | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo CN | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| -| **Độ phức tạp** | Dễ | Dễ | Dễ | Trung bình | Trung bình | Khó | Khó | Rất dễ | -| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Bridge | WebSocket | +| **Độ phức tạp** | Dễ | Dễ | Dễ | Trung bình | Trung bình | Khó | Trung bình | Rất dễ | +| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Baileys Bridge | WebSocket | | **Hỗ trợ DM** | Có | Có | Có | Có | Có | Có | Có | N/A | | **Hỗ trợ nhóm** | Có | Có | Có | Có | Không | Có | Có | N/A | | **Streaming** | Có | Có | Có | Có | Không | Không | Không | Có | -| **Định dạng** | HTML | Markdown | mrkdwn | Cards | Plain | Plain | JSON | JSON | -| **Media** | Ảnh, Voice, File | File, Embeds | File (20MB) | Ảnh, File | Ảnh | -- | JSON | N/A | -| **Xác thực** | Token | Token | 3 Token | App ID + Secret | API Key | Credentials | Bridge | Token + Pairing | +| **Định dạng** | HTML | Markdown | mrkdwn | Cards | Plain | Plain | WA native | JSON | +| **Media** | Ảnh, Voice, File | File, Embeds | File (20MB) | Ảnh, File | Ảnh | -- | Ảnh, Video, Audio, Docs | N/A | +| **Xác thực** | Token | Token | 3 Token | App ID + Secret | API Key | Credentials | QR Code | Token + Pairing | | **Mức rủi ro** | Thấp | Thấp | Thấp | Thấp | Thấp | Cao | Trung bình | Thấp | ## File cấu hình diff --git a/vi/channels/whatsapp.md b/vi/channels/whatsapp.md index b61c4f2..558c01d 100644 --- a/vi/channels/whatsapp.md +++ b/vi/channels/whatsapp.md @@ -2,27 +2,48 @@ # Channel WhatsApp -Tích hợp WhatsApp qua WebSocket bridge bên ngoài. GoClaw kết nối với dịch vụ bridge (ví dụ: whatsapp-web.js) để xử lý giao thức WhatsApp. +Tích hợp WhatsApp qua bridge WebSocket dựa trên Baileys. GoClaw kết nối như WS client đến bridge, bridge xử lý giao thức multi-device của WhatsApp (không cần Chrome). ## Thiết lập -**Yêu cầu:** -- Dịch vụ WhatsApp bridge đang chạy (ví dụ: whatsapp-web.js) -- URL bridge có thể truy cập từ GoClaw +### Bắt đầu nhanh (Docker Compose) -**Khởi động WhatsApp Bridge:** +Cách nhanh nhất để chạy WhatsApp là dùng Docker Compose overlay đi kèm: -Ví dụ dùng whatsapp-web.js: +```bash +docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.whatsapp.yml up -d +``` + +Sau đó trong giao diện GoClaw: +1. **Channels > Add Channel > WhatsApp** +2. Đặt **Bridge URL** thành `ws://whatsapp-bridge:3001` +3. Chọn agent, bấm **Create & Scan QR** +4. Quét QR bằng WhatsApp (Bạn > Thiết bị liên kết > Liên kết thiết bị) + +### Chạy Bridge thủ công + +Nếu bạn muốn chạy bridge ngoài Docker: ```bash -npm install -g whatsapp-web.js -# Khởi động bridge server trên localhost:3001 -whatsapp-bridge --port 3001 +cd bridge/whatsapp +npm install +node server.js ``` -Bridge của bạn cần expose một WebSocket endpoint (ví dụ: `ws://localhost:3001`). +Biến môi trường: -**Bật WhatsApp:** +| Biến | Mặc định | Mô tả | +|------|---------|-------| +| `BRIDGE_PORT` | `3001` | Cổng WebSocket server | +| `AUTH_DIR` | `./auth_info` | Thư mục lưu trạng thái xác thực WhatsApp | +| `MEDIA_DIR` | Thư mục temp hệ thống | Thư mục lưu media tải về | +| `MEDIA_MAX_BYTES` | `20971520` (20 MB) | Kích thước media tối đa | +| `LOG_LEVEL` | `silent` | Mức log bridge (`silent`, `warn`) | +| `PRINT_QR` | `false` | In QR code ra terminal (hữu ích khi không có UI) | + +### Cấu hình qua file config + +Cho channel cấu hình qua file (thay vì DB instance): ```json { @@ -30,9 +51,8 @@ Bridge của bạn cần expose một WebSocket endpoint (ví dụ: `ws://localh "whatsapp": { "enabled": true, "bridge_url": "ws://localhost:3001", - "dm_policy": "open", - "group_policy": "open", - "allow_from": [] + "dm_policy": "pairing", + "group_policy": "pairing" } } } @@ -40,104 +60,169 @@ Bridge của bạn cần expose một WebSocket endpoint (ví dụ: `ws://localh ## Cấu hình -Tất cả config key nằm trong `channels.whatsapp`: +Tất cả config key nằm trong `channels.whatsapp` (file config) hoặc config JSON của instance (DB): | Key | Kiểu | Mặc định | Mô tả | -|-----|------|---------|-------------| -| `enabled` | bool | false | Bật/tắt channel | +|-----|------|---------|-------| +| `enabled` | bool | `false` | Bật/tắt channel | | `bridge_url` | string | bắt buộc | URL WebSocket đến bridge (ví dụ: `ws://bridge:3001`) | | `allow_from` | list | -- | Danh sách trắng user/group ID | -| `dm_policy` | string | `"open"` | `open`, `allowlist`, `pairing`, `disabled` | -| `group_policy` | string | `"open"` | `open`, `allowlist`, `disabled` | +| `dm_policy` | string | `"pairing"` | `pairing`, `open`, `allowlist`, `disabled` | +| `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | `pairing`, `open`, `allowlist`, `disabled` | +| `require_mention` | bool | `false` | Chỉ trả lời trong nhóm khi bot được @mention | | `block_reply` | bool | -- | Ghi đè block_reply của gateway (nil=kế thừa) | -## Tính năng - -### Kết nối Bridge - -GoClaw kết nối với bridge qua WebSocket và gửi/nhận JSON message. +## Kiến trúc ```mermaid flowchart LR - GC["GoClaw"] - WS["WebSocket
Connection"] - BRIDGE["WhatsApp
Bridge"] WA["WhatsApp
Servers"] + BRIDGE["Baileys Bridge
(Node.js WS Server)"] + GC["GoClaw
(WS Client)"] + UI["Web UI
(QR Wizard)"] - GC -->|"JSON messages"| WS - WS -->|"JSON messages"| BRIDGE - BRIDGE -->|"WhatsApp protocol"| WA - WA -->|"Protocol"| BRIDGE - BRIDGE -->|"JSON events"| WS - WS -->|"Events"| GC + WA <-->|"Giao thức multi-device"| BRIDGE + BRIDGE <-->|"JSON qua WebSocket"| GC + GC -->|"QR event qua WS bus"| UI ``` -### Hỗ trợ DM và Nhóm +- **Bridge** là WebSocket **server** (mặc định cổng 3001) +- **GoClaw** kết nối như **client** và xử lý routing, AI, pairing +- Một bridge instance = một số điện thoại WhatsApp +- File media được trao đổi qua shared volume (`/tmp/goclaw_wa_media`) -Bridge phát hiện group chat qua hậu tố `@g.us` trong chat ID: +## Tính năng -- **DM**: `"1234567890@c.us"` -- **Nhóm**: `"123-456@g.us"` +### Xác thực QR Code -Chính sách được áp dụng tương ứng (chính sách DM cho DM, chính sách nhóm cho nhóm). +WhatsApp yêu cầu quét QR để liên kết thiết bị. Quy trình: -Trong chat nhóm, tin nhắn bao gồm chú thích `[From:]` với tên hiển thị của người gửi, giúp agent phân biệt giữa các thành viên. +1. Bridge tạo QR qua kết nối Baileys +2. Bridge gửi `{type: "qr", data: ""}` đến GoClaw +3. GoClaw mã hóa thành PNG và broadcast qua bus event +4. Web UI wizard hiển thị ảnh QR +5. Người dùng quét bằng WhatsApp (Bạn > Thiết bị liên kết > Liên kết thiết bị) +6. Bridge xác nhận xác thực: `{type: "status", connected: true}` -### Định dạng tin nhắn +**Xác thực lại**: Dùng nút "Re-authenticate" trong bảng channels để buộc quét QR mới (đăng xuất phiên WhatsApp hiện tại). -Tin nhắn là JSON object: +### Chính sách DM và Nhóm -```json -{ - "from": "1234567890@c.us", - "body": "Hello!", - "type": "chat", - "id": "message_id_123" -} -``` +Nhóm WhatsApp có chat ID kết thúc bằng `@g.us`: -Media được truyền dạng mảng đường dẫn file: +- **DM**: `"1234567890@s.whatsapp.net"` +- **Nhóm**: `"120363012345@g.us"` -```json -{ - "from": "1234567890@c.us", - "body": "Photo", - "media": ["/tmp/photo.jpg"], - "type": "image" -} -``` +Các chính sách có sẵn: -### Tự động Kết nối lại +| Chính sách | Hành vi | +|-----------|---------| +| `open` | Chấp nhận tất cả tin nhắn | +| `pairing` | Yêu cầu phê duyệt mã pairing (mặc định cho DB instance) | +| `allowlist` | Chỉ user trong `allow_from` | +| `disabled` | Từ chối tất cả tin nhắn | -Nếu kết nối bridge bị đứt: -- Exponential backoff: 1s → tối đa 30s -- Thử kết nối lại liên tục -- Log cảnh báo khi kết nối lại thất bại +Chính sách `pairing` cho nhóm: nhóm chưa ghép nối nhận mã pairing. Phê duyệt qua `goclaw pairing approve `. -## Pattern phổ biến +### @Mention Gating -### Gửi đến Chat +Khi `require_mention` là `true`, bot chỉ trả lời trong nhóm khi được @mention trực tiếp. Fail-closed — nếu JID của bot chưa xác định, tin nhắn sẽ bị bỏ qua. -```go -manager.SendToChannel(ctx, "whatsapp", "1234567890@c.us", "Hello!") -``` +### Hỗ trợ Media -### Kiểm tra xem Chat có phải Nhóm không +Bridge tải media đến (ảnh, video, audio, tài liệu, sticker) vào shared volume. GoClaw đọc các file này và chuyển vào pipeline agent. -```go -isGroup := strings.HasSuffix(chatID, "@g.us") +Loại media đến được hỗ trợ: image, video, audio, document, sticker. + +Media đi: GoClaw ghi file vào shared volume và gửi đường dẫn đến bridge để gửi đi. + +**Shared volume** (Docker): Cả container `goclaw` và `whatsapp-bridge` mount cùng volume tại `/tmp/goclaw_wa_media`. + +### Định dạng tin nhắn + +Output LLM được chuyển đổi từ Markdown sang định dạng native của WhatsApp: + +| Markdown | WhatsApp | Hiển thị | +|----------|----------|---------| +| `**bold**` | `*bold*` | **bold** | +| `_italic_` | `_italic_` | _italic_ | +| `~~strikethrough~~` | `~strikethrough~` | ~~strikethrough~~ | +| `` `inline code` `` | ` ```code``` ` | `code` | +| `# Header` | `*Header*` | **Header** | +| `[text](url)` | `text url` | text url | +| `- list item` | `* list item` | * list item | + +Fenced code block được giữ nguyên dạng ` ``` `. Tag HTML từ output LLM được tiền xử lý thành Markdown trước khi chuyển đổi. + +### Chỉ báo đang nhập + +GoClaw hiển thị "đang nhập..." trong WhatsApp khi agent xử lý tin nhắn. WhatsApp xóa chỉ báo sau ~10 giây, nên GoClaw làm mới mỗi 8 giây cho đến khi gửi trả lời. + +### Tự động kết nối lại + +Nếu kết nối bridge bị đứt: +- Exponential backoff: 1s > 2s > 4s > ... > tối đa 30s +- Thử lại liên tục cho đến khi bridge khả dụng +- Trạng thái sức khỏe channel được cập nhật (degraded/healthy) + +## Giao thức Bridge + +### Bridge > GoClaw + +| Loại | Payload | Mô tả | +|------|---------|-------| +| `status` | `{connected: bool, me: "jid"}` | Trạng thái xác thực (gửi khi kết nối + thay đổi) | +| `qr` | `{data: "qr-string"}` | QR code để quét | +| `message` | `{id, from, chat, content, from_name, is_group, mentioned_jids, media}` | Tin nhắn đến | +| `pong` | `{}` | Phản hồi ping | + +### GoClaw > Bridge + +| Loại | Payload | Mô tả | +|------|---------|-------| +| `message` | `{to: "jid", content: "text"}` | Gửi tin nhắn | +| `command` | `{action: "reauth"}` | Đăng xuất + khởi động lại QR | +| `command` | `{action: "ping"}` | Kiểm tra sức khỏe | +| `command` | `{action: "presence", to, state}` | Presence (composing/paused) | + +## Docker Compose + +File `docker-compose.whatsapp.yml` overlay thêm dịch vụ bridge: + +```yaml +services: + whatsapp-bridge: + build: ./bridge/whatsapp + ports: + - "3001:3001" + volumes: + - wa_auth:/app/auth_info # Trạng thái xác thực bền vững + - wa_media:/tmp/goclaw_wa_media # Shared media volume + environment: + - BRIDGE_PORT=3001 + - PRINT_QR=false + + goclaw: + volumes: + - wa_media:/tmp/goclaw_wa_media # Cùng media volume + +volumes: + wa_auth: + wa_media: ``` ## Xử lý sự cố | Vấn đề | Giải pháp | -|-------|----------| -| "Connection refused" | Xác minh bridge đang chạy. Kiểm tra `bridge_url` đúng và có thể truy cập. | -| "WebSocket: close normal closure" | Bridge tắt graceful. Khởi động lại dịch vụ bridge. | -| Liên tục thử kết nối lại | Bridge bị down hoặc không thể truy cập. Kiểm tra log bridge. | -| Không nhận được tin nhắn | Xác minh bridge đang nhận WhatsApp event. Kiểm tra log bridge. | -| Phát hiện nhóm thất bại | Đảm bảo chat ID kết thúc bằng `@g.us` cho nhóm, `@c.us` cho DM. | -| Media không được gửi | Đảm bảo đường dẫn file có thể truy cập từ bridge. Kiểm tra bridge có hỗ trợ media không. | +|--------|----------| +| "Connection refused" | Xác minh bridge đang chạy và `bridge_url` đúng. Với Docker, dùng `ws://whatsapp-bridge:3001`. | +| Không hiển thị QR | Kiểm tra log bridge. Đảm bảo bridge kết nối được WhatsApp server. Thử `PRINT_QR=true` để hiện QR trong terminal. | +| Quét QR nhưng không xác thực | Trạng thái xác thực có thể bị hỏng. Xóa thư mục `auth_info/` và khởi động lại bridge. | +| Không nhận tin nhắn | Kiểm tra giao thức bridge: phải gửi `type:"message"` với field `from`/`content` (không phải `sender`/`body`). | +| Không nhận media | Đảm bảo shared volume được mount trong cả hai container. Kiểm tra giới hạn `MEDIA_MAX_BYTES`. | +| Cảnh báo "Bridge format mismatch" | Bridge gửi tin nhắn thiếu field `type`. Thêm `type:"message"` và dùng tên field `from`/`content`. | +| Chỉ báo đang nhập bị kẹt | GoClaw tự hủy typing khi gửi trả lời. Nếu bị kẹt, kết nối bridge có thể đã đứt. | +| Tin nhắn nhóm bị bỏ qua | Kiểm tra `group_policy`. Nếu là `pairing`, nhóm cần phê duyệt. Nếu `require_mention` là true, @mention bot. | ## Tiếp theo @@ -146,4 +231,4 @@ isGroup := strings.HasSuffix(chatID, "@g.us") - [Larksuite](/channel-feishu) — Tích hợp Larksuite - [Browser Pairing](/channel-browser-pairing) — Luồng pairing - + diff --git a/zh/channels/INDEX.md b/zh/channels/INDEX.md index 701719f..c6839f9 100644 --- a/zh/channels/INDEX.md +++ b/zh/channels/INDEX.md @@ -13,7 +13,7 @@ GoClaw 所有消息平台集成的完整文档。 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook、流式卡片、媒体 6. **[Zalo OA](./zalo-oa.md)** — 官方账号、仅 DM、配对、图片 7. **[Zalo 个人](./zalo-personal.md)** — 个人账号(非官方)、DM + 群组 -8. **[WhatsApp](./whatsapp.md)** — 外部桥接、JSON 协议、自动重连 +8. **[WhatsApp](./whatsapp.md)** — Baileys 桥接、QR 认证、媒体、输入指示器、配对 9. **[WebSocket](./websocket.md)** — 直接 RPC、自定义客户端、流式事件 10. **[Browser Pairing](./browser-pairing.md)** — 8 位码认证、session token @@ -21,15 +21,15 @@ GoClaw 所有消息平台集成的完整文档。 | 功能 | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo 个人 | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| -| **设置复杂度** | 简单 | 简单 | 简单 | 中等 | 中等 | 困难 | 困难 | 非常简单 | -| **传输方式** | 轮询 | Gateway | Socket Mode | WS/Webhook | 轮询 | 协议 | 桥接 | WebSocket | +| **设置复杂度** | 简单 | 简单 | 简单 | 中等 | 中等 | 困难 | 中等 | 非常简单 | +| **传输方式** | 轮询 | Gateway | Socket Mode | WS/Webhook | 轮询 | 协议 | Baileys 桥接 | WebSocket | | **DM 支持** | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 无 | | **群组支持** | 是 | 是 | 是 | 是 | 否 | 是 | 是 | 无 | | **流式输出** | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 是 | -| **富文本格式** | HTML | Markdown | mrkdwn | 卡片 | 纯文本 | 纯文本 | JSON | JSON | +| **富文本格式** | HTML | Markdown | mrkdwn | 卡片 | 纯文本 | 纯文本 | WA 原生 | JSON | | **表情回应** | 是 | -- | 是 | 是 | -- | -- | -- | -- | -| **媒体** | 图片、语音、文件 | 文件、嵌入 | 文件(20MB) | 图片、文件 | 图片 | -- | JSON | 无 | -| **认证方式** | Token | Token | 3 Tokens | App ID + Secret | API Key | 凭据 | 桥接 | Token + 配对 | +| **媒体** | 图片、语音、文件 | 文件、嵌入 | 文件(20MB) | 图片、文件 | 图片 | -- | 图片、视频、音频、文档 | 无 | +| **认证方式** | Token | Token | 3 Tokens | App ID + Secret | API Key | 凭据 | QR 码 | Token + 配对 | | **风险等级** | 低 | 低 | 低 | 低 | 低 | 高 | 中 | 低 | ## 配置文件 @@ -144,9 +144,11 @@ GoClaw 所有消息平台集成的完整文档。 ### WhatsApp -- [ ] 部署 WhatsApp 桥接服务(如 whatsapp-web.js) -- [ ] 复制 WebSocket URL -- [ ] 在配置中启用 +- [ ] 部署桥接:`docker compose -f docker-compose.whatsapp.yml up -d`(或 `cd bridge/whatsapp && npm install && node server.js`) +- [ ] 在 UI 中创建 channel:Channels > Add Channel > WhatsApp +- [ ] 设置 Bridge URL(如 `ws://whatsapp-bridge:3001`) +- [ ] 用 WhatsApp 扫描 QR 码(你 > 已关联的设备 > 关联设备) +- [ ] 根据需要配置 DM/群组策略 ### WebSocket diff --git a/zh/channels/whatsapp.md b/zh/channels/whatsapp.md index 31c6754..0c9d3b5 100644 --- a/zh/channels/whatsapp.md +++ b/zh/channels/whatsapp.md @@ -2,27 +2,48 @@ # WhatsApp Channel -通过外部 WebSocket 桥接集成 WhatsApp。GoClaw 连接到处理 WhatsApp 协议的桥接服务(如 whatsapp-web.js)。 +通过基于 Baileys 的外部 WebSocket 桥接集成 WhatsApp。GoClaw 作为 WS 客户端连接到桥接,桥接处理 WhatsApp 多设备协议(无需 Chrome)。 ## 设置 -**前置条件:** -- 运行中的 WhatsApp 桥接服务(如 whatsapp-web.js) -- GoClaw 可访问的桥接 URL +### 快速开始(Docker Compose) -**启动 WhatsApp 桥接:** +最快的方式是使用自带的 Docker Compose overlay: -以 whatsapp-web.js 为例: +```bash +docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.whatsapp.yml up -d +``` + +然后在 GoClaw 界面中: +1. **Channels > Add Channel > WhatsApp** +2. 将 **Bridge URL** 设为 `ws://whatsapp-bridge:3001` +3. 选择 agent,点击 **Create & Scan QR** +4. 用 WhatsApp 扫描 QR 码(你 > 已关联的设备 > 关联设备) + +### 手动运行桥接 + +如果您想在 Docker 外运行桥接: ```bash -npm install -g whatsapp-web.js -# 在 localhost:3001 启动桥接服务器 -whatsapp-bridge --port 3001 +cd bridge/whatsapp +npm install +node server.js ``` -桥接应暴露 WebSocket 端点(如 `ws://localhost:3001`)。 +环境变量: -**启用 WhatsApp:** +| 变量 | 默认值 | 说明 | +|------|--------|------| +| `BRIDGE_PORT` | `3001` | WebSocket 服务端口 | +| `AUTH_DIR` | `./auth_info` | WhatsApp 认证状态存储目录 | +| `MEDIA_DIR` | 系统临时目录 | 下载媒体文件存储目录 | +| `MEDIA_MAX_BYTES` | `20971520`(20 MB) | 最大媒体下载大小 | +| `LOG_LEVEL` | `silent` | 桥接日志级别(`silent`、`warn`) | +| `PRINT_QR` | `false` | 在终端打印 QR 码(无 UI 时有用) | + +### 配置文件设置 + +通过配置文件(而非 DB 实例)设置 channel: ```json { @@ -30,9 +51,8 @@ whatsapp-bridge --port 3001 "whatsapp": { "enabled": true, "bridge_url": "ws://localhost:3001", - "dm_policy": "open", - "group_policy": "open", - "allow_from": [] + "dm_policy": "pairing", + "group_policy": "pairing" } } } @@ -40,104 +60,169 @@ whatsapp-bridge --port 3001 ## 配置 -所有配置项位于 `channels.whatsapp`: +所有配置项位于 `channels.whatsapp`(配置文件)或实例配置 JSON(DB): | 配置项 | 类型 | 默认值 | 说明 | -|-----|------|---------|-------------| -| `enabled` | bool | false | 启用/禁用 channel | +|--------|------|--------|------| +| `enabled` | bool | `false` | 启用/禁用 channel | | `bridge_url` | string | 必填 | 到桥接的 WebSocket URL(如 `ws://bridge:3001`) | | `allow_from` | list | -- | 用户/群组 ID 白名单 | -| `dm_policy` | string | `"open"` | `open`、`allowlist`、`pairing`、`disabled` | -| `group_policy` | string | `"open"` | `open`、`allowlist`、`disabled` | +| `dm_policy` | string | `"pairing"` | `pairing`、`open`、`allowlist`、`disabled` | +| `group_policy` | string | `"pairing"`(DB)/ `"open"`(配置) | `pairing`、`open`、`allowlist`、`disabled` | +| `require_mention` | bool | `false` | 仅在群组中被 @提及时回复 | | `block_reply` | bool | -- | 覆盖 gateway block_reply(nil=继承) | -## 功能特性 - -### 桥接连接 - -GoClaw 通过 WebSocket 连接到桥接,发送/接收 JSON 消息。 +## 架构 ```mermaid flowchart LR - GC["GoClaw"] - WS["WebSocket
连接"] - BRIDGE["WhatsApp
桥接"] WA["WhatsApp
服务器"] + BRIDGE["Baileys 桥接
(Node.js WS Server)"] + GC["GoClaw
(WS Client)"] + UI["Web UI
(QR 向导)"] - GC -->|"JSON 消息"| WS - WS -->|"JSON 消息"| BRIDGE - BRIDGE -->|"WhatsApp 协议"| WA - WA -->|"协议"| BRIDGE - BRIDGE -->|"JSON 事件"| WS - WS -->|"事件"| GC + WA <-->|"多设备协议"| BRIDGE + BRIDGE <-->|"WebSocket JSON"| GC + GC -->|"QR 事件通过 WS bus"| UI ``` -### DM 和群组支持 +- **桥接**是 WebSocket **服务器**(默认端口 3001) +- **GoClaw** 作为**客户端**连接,处理路由、AI、配对 +- 一个桥接实例 = 一个 WhatsApp 手机号 +- 媒体文件通过共享卷交换(`/tmp/goclaw_wa_media`) -桥接通过 chat ID 后缀 `@g.us` 检测群聊: +## 功能特性 -- **DM**:`"1234567890@c.us"` -- **群组**:`"123-456@g.us"` +### QR 码认证 -策略相应应用(DM 使用 DM 策略,群组使用群组策略)。 +WhatsApp 需要扫描 QR 码来关联设备。流程: -在群聊中,消息包含 `[From:]` 标注和发送者的显示名,让 agent 能够区分参与者。 +1. 桥接通过 Baileys 连接生成 QR +2. 桥接发送 `{type: "qr", data: ""}` 给 GoClaw +3. GoClaw 编码为 PNG 并通过 bus 事件广播 +4. Web UI 向导显示 QR 图片 +5. 用户用 WhatsApp 扫描(你 > 已关联的设备 > 关联设备) +6. 桥接确认认证:`{type: "status", connected: true}` -### 消息格式 +**重新认证**:在 channels 表中点击"Re-authenticate"按钮强制新 QR 扫描(登出当前 WhatsApp 会话)。 -消息为 JSON 对象: +### DM 和群组策略 -```json -{ - "from": "1234567890@c.us", - "body": "Hello!", - "type": "chat", - "id": "message_id_123" -} -``` +WhatsApp 群组的 chat ID 以 `@g.us` 结尾: -媒体以文件路径数组传递: +- **DM**:`"1234567890@s.whatsapp.net"` +- **群组**:`"120363012345@g.us"` -```json -{ - "from": "1234567890@c.us", - "body": "Photo", - "media": ["/tmp/photo.jpg"], - "type": "image" -} -``` +可用策略: -### 自动重连 +| 策略 | 行为 | +|------|------| +| `open` | 接受所有消息 | +| `pairing` | 需要配对码审批(DB 实例默认) | +| `allowlist` | 仅 `allow_from` 中的用户 | +| `disabled` | 拒绝所有消息 | -若桥接连接断开: -- 指数退避:1s → 最大 30s -- 持续重试 -- 重连失败时日志警告 +群组 `pairing` 策略:未配对的群组会收到配对码回复。通过 `goclaw pairing approve ` 审批。 -## 常用模式 +### @提及过滤 -### 发送到聊天 +当 `require_mention` 为 `true` 时,机器人仅在群聊中被明确 @提及时才回复。失败关闭 —— 如果机器人的 JID 未知,消息将被忽略。 -```go -manager.SendToChannel(ctx, "whatsapp", "1234567890@c.us", "Hello!") -``` +### 媒体支持 + +桥接将收到的媒体(图片、视频、音频、文档、贴纸)下载到共享卷。GoClaw 读取这些文件并传入 agent 管道。 + +支持的入站媒体类型:image、video、audio、document、sticker。 + +出站媒体:GoClaw 将文件写入共享卷,发送路径给桥接进行投递。 + +**共享卷**(Docker):`goclaw` 和 `whatsapp-bridge` 容器都挂载同一卷到 `/tmp/goclaw_wa_media`。 -### 检查是否为群组 +### 消息格式化 -```go -isGroup := strings.HasSuffix(chatID, "@g.us") +LLM 输出从 Markdown 转换为 WhatsApp 原生格式: + +| Markdown | WhatsApp | 显示效果 | +|----------|----------|----------| +| `**bold**` | `*bold*` | **bold** | +| `_italic_` | `_italic_` | _italic_ | +| `~~strikethrough~~` | `~strikethrough~` | ~~strikethrough~~ | +| `` `inline code` `` | ` ```code``` ` | `code` | +| `# Header` | `*Header*` | **Header** | +| `[text](url)` | `text url` | text url | +| `- list item` | `* list item` | * list item | + +围栏代码块保持为 ` ``` `。来自 LLM 输出的 HTML 标签在转换前预处理为 Markdown 等效形式。 + +### 输入指示器 + +GoClaw 在 agent 处理消息时在 WhatsApp 中显示"正在输入..."。WhatsApp 在约 10 秒后清除指示器,因此 GoClaw 每 8 秒刷新一次直到回复发送。 + +### 自动重连 + +若桥接连接断开: +- 指数退避:1s > 2s > 4s > ... > 最大 30s +- 持续重试直到桥接可用 +- Channel 健康状态更新(degraded/healthy) + +## 桥接协议 + +### 桥接 > GoClaw + +| 类型 | 负载 | 说明 | +|------|------|------| +| `status` | `{connected: bool, me: "jid"}` | 认证状态(连接时和变更时发送) | +| `qr` | `{data: "qr-string"}` | 用于扫描的 QR 码 | +| `message` | `{id, from, chat, content, from_name, is_group, mentioned_jids, media}` | 收到的消息 | +| `pong` | `{}` | ping 的响应 | + +### GoClaw > 桥接 + +| 类型 | 负载 | 说明 | +|------|------|------| +| `message` | `{to: "jid", content: "text"}` | 发送消息 | +| `command` | `{action: "reauth"}` | 登出 + 重启 QR 流程 | +| `command` | `{action: "ping"}` | 健康检查 | +| `command` | `{action: "presence", to, state}` | 在线状态(composing/paused) | + +## Docker Compose + +`docker-compose.whatsapp.yml` overlay 添加桥接服务: + +```yaml +services: + whatsapp-bridge: + build: ./bridge/whatsapp + ports: + - "3001:3001" + volumes: + - wa_auth:/app/auth_info # 持久化认证状态 + - wa_media:/tmp/goclaw_wa_media # 共享媒体卷 + environment: + - BRIDGE_PORT=3001 + - PRINT_QR=false + + goclaw: + volumes: + - wa_media:/tmp/goclaw_wa_media # 同一媒体卷 + +volumes: + wa_auth: + wa_media: ``` ## 故障排查 | 问题 | 解决方案 | -|-------|----------| -| "Connection refused" | 验证桥接是否运行。检查 `bridge_url` 是否正确且可访问。 | -| "WebSocket: close normal closure" | 桥接已优雅关闭。重启桥接服务。 | -| 持续重连尝试 | 桥接已关闭或不可达。检查桥接日志。 | -| 未收到消息 | 验证桥接是否接收 WhatsApp 事件。检查桥接日志。 | -| 群组检测失败 | 确保群组 chat ID 以 `@g.us` 结尾,DM 以 `@c.us` 结尾。 | -| 媒体未发送 | 确保文件路径对桥接可访问。检查桥接是否支持媒体。 | +|------|----------| +| "Connection refused" | 验证桥接正在运行且 `bridge_url` 正确。Docker 环境使用 `ws://whatsapp-bridge:3001`。 | +| 不显示 QR 码 | 检查桥接日志。确保桥接能连接 WhatsApp 服务器。尝试 `PRINT_QR=true` 在终端显示 QR。 | +| 扫描 QR 但未认证 | 认证状态可能损坏。删除 `auth_info/` 目录并重启桥接。 | +| 未收到消息 | 检查桥接协议:必须发送 `type:"message"` 且包含 `from`/`content` 字段(不是 `sender`/`body`)。 | +| 未收到媒体 | 确保两个容器都挂载了共享卷。检查 `MEDIA_MAX_BYTES` 限制。 | +| "Bridge format mismatch" 警告 | 桥接发送的消息缺少 `type` 字段。添加 `type:"message"` 并使用 `from`/`content` 字段名。 | +| 输入指示器卡住 | GoClaw 在发送回复时自动取消 typing。如果卡住,桥接连接可能已断开。 | +| 群组消息被忽略 | 检查 `group_policy`。如果是 `pairing`,群组需要审批。如果 `require_mention` 为 true,@提及机器人。 | ## 下一步 @@ -146,4 +231,4 @@ isGroup := strings.HasSuffix(chatID, "@g.us") - [Larksuite](/channel-feishu) — Larksuite 集成 - [Browser Pairing](/channel-browser-pairing) — 配对流程 - + From 83d8213072acd91039cd1fa368366ce61a5ee851 Mon Sep 17 00:00:00 2001 From: Duc Nguyen Date: Mon, 6 Apr 2026 18:48:03 +0700 Subject: [PATCH 2/4] docs(whatsapp): update for native WhatsApp integration - Remove external service references from setup, config, and architecture - Simplify setup to 3 steps (create channel, scan QR, configure policies) - Update architecture diagram to show direct connection - Add migration section for users on the old setup - Add history_limit config, LID addressing section - Fix inline code formatting row in conversion table - Simplify setup checklist in INDEX.md - All 3 locales updated (en, vi, zh) --- channels/INDEX.md | 6 +- channels/whatsapp.md | 173 +++++++++++++--------------------------- vi/channels/INDEX.md | 4 +- vi/channels/whatsapp.md | 173 +++++++++++++--------------------------- zh/channels/INDEX.md | 6 +- zh/channels/whatsapp.md | 173 +++++++++++++--------------------------- 6 files changed, 171 insertions(+), 364 deletions(-) diff --git a/channels/INDEX.md b/channels/INDEX.md index 3f6b004..e94353b 100644 --- a/channels/INDEX.md +++ b/channels/INDEX.md @@ -11,7 +11,7 @@ Complete documentation for all messaging platform integrations in GoClaw. 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook, streaming cards, media 6. **[Zalo OA](./zalo-oa.md)** — Official Account, DM-only, pairing, images 7. **[Zalo Personal](./zalo-personal.md)** — Personal account (unofficial), DM + groups -8. **[WhatsApp](./whatsapp.md)** — Baileys bridge, QR auth, media, typing indicators, pairing +8. **[WhatsApp](./whatsapp.md)** — Native (whatsmeow), QR auth, media, typing indicators, pairing 9. **[WebSocket](./websocket.md)** — Direct RPC, custom clients, streaming events 10. **[Browser Pairing](./browser-pairing.md)** — 8-char code auth, session tokens @@ -20,7 +20,7 @@ Complete documentation for all messaging platform integrations in GoClaw. | Feature | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo Pers | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| | **Setup Complexity** | Easy | Easy | Easy | Medium | Medium | Hard | Medium | Very Easy | -| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Baileys Bridge | WebSocket | +| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Native (whatsmeow) | WebSocket | | **DM Support** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | N/A | | **Group Support** | Yes | Yes | Yes | Yes | No | Yes | Yes | N/A | | **Streaming** | Yes | Yes | Yes | Yes | No | No | No | Yes | @@ -142,9 +142,7 @@ Flexible format supporting: ### WhatsApp -- [ ] Deploy bridge: `docker compose -f docker-compose.whatsapp.yml up -d` (or `cd bridge/whatsapp && npm install && node server.js`) - [ ] Create channel in UI: Channels > Add Channel > WhatsApp -- [ ] Set Bridge URL (e.g., `ws://whatsapp-bridge:3001`) - [ ] Scan QR code with WhatsApp (You > Linked Devices > Link a Device) - [ ] Configure DM/group policies as needed diff --git a/channels/whatsapp.md b/channels/whatsapp.md index 25677fa..5d1438e 100644 --- a/channels/whatsapp.md +++ b/channels/whatsapp.md @@ -1,43 +1,15 @@ # WhatsApp Channel -WhatsApp integration via an external Baileys-based WebSocket bridge. GoClaw connects as a WS client to the bridge, which handles the WhatsApp multi-device protocol (no Chrome required). +Native WhatsApp integration via [whatsmeow](https://github.com/tulir/whatsmeow). GoClaw connects directly to WhatsApp's multi-device protocol — no external bridge or Node.js service required. Auth state is stored in the database (PostgreSQL or SQLite). ## Setup -### Quick Start (Docker Compose) - -The fastest way to run WhatsApp is with the included Docker Compose overlay: - -```bash -docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.whatsapp.yml up -d -``` - -Then in the GoClaw UI: 1. **Channels > Add Channel > WhatsApp** -2. Set **Bridge URL** to `ws://whatsapp-bridge:3001` -3. Choose an agent, click **Create & Scan QR** -4. Scan the QR code with WhatsApp (You > Linked Devices > Link a Device) - -### Manual Bridge Setup - -If you prefer running the bridge outside Docker: - -```bash -cd bridge/whatsapp -npm install -node server.js -``` - -Environment variables: +2. Choose an agent, click **Create & Scan QR** +3. Scan the QR code with WhatsApp (You > Linked Devices > Link a Device) +4. Configure DM/group policies as needed -| Variable | Default | Description | -|----------|---------|-------------| -| `BRIDGE_PORT` | `3001` | WebSocket server port | -| `AUTH_DIR` | `./auth_info` | Directory for WhatsApp auth state | -| `MEDIA_DIR` | OS temp dir | Directory for downloaded media files | -| `MEDIA_MAX_BYTES` | `20971520` (20 MB) | Max media download size | -| `LOG_LEVEL` | `silent` | Bridge log level (`silent`, `warn`) | -| `PRINT_QR` | `false` | Print QR code to terminal (useful without UI) | +That's it — no bridge to deploy, no extra containers. ### Config File Setup @@ -48,7 +20,6 @@ For config-file-based channels (instead of DB instances): "channels": { "whatsapp": { "enabled": true, - "bridge_url": "ws://localhost:3001", "dm_policy": "pairing", "group_policy": "pairing" } @@ -63,11 +34,11 @@ All config keys are in `channels.whatsapp` (config file) or the instance config | Key | Type | Default | Description | |-----|------|---------|-------------| | `enabled` | bool | `false` | Enable/disable channel | -| `bridge_url` | string | required | WebSocket URL to bridge (e.g., `ws://bridge:3001`) | | `allow_from` | list | -- | User/group ID allowlist | | `dm_policy` | string | `"pairing"` | `pairing`, `open`, `allowlist`, `disabled` | | `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | `pairing`, `open`, `allowlist`, `disabled` | | `require_mention` | bool | `false` | Only respond in groups when bot is @mentioned | +| `history_limit` | int | `200` | Max pending group messages for context (0=disabled) | | `block_reply` | bool | -- | Override gateway block_reply (nil=inherit) | ## Architecture @@ -75,19 +46,17 @@ All config keys are in `channels.whatsapp` (config file) or the instance config ```mermaid flowchart LR WA["WhatsApp
Servers"] - BRIDGE["Baileys Bridge
(Node.js WS Server)"] - GC["GoClaw
(WS Client)"] + GC["GoClaw
(whatsmeow)"] UI["Web UI
(QR Wizard)"] - WA <-->|"Multi-device protocol"| BRIDGE - BRIDGE <-->|"JSON over WebSocket"| GC - GC -->|"QR events via WS bus"| UI + WA <-->|"Multi-device protocol"| GC + GC -->|"QR events via WS"| UI ``` -- **Bridge** is the WebSocket **server** (default port 3001) -- **GoClaw** connects as a **client** and handles routing, AI, pairing -- One bridge instance = one WhatsApp phone number -- Media files are exchanged via a shared volume (`/tmp/goclaw_wa_media`) +- **GoClaw** connects directly to WhatsApp servers via whatsmeow (Go library) +- Auth state is stored in the database — survives restarts +- One channel instance = one WhatsApp phone number +- No bridge, no Node.js, no shared volumes ## Features @@ -95,14 +64,13 @@ flowchart LR WhatsApp requires QR code scanning to link a device. The flow: -1. Bridge generates QR via Baileys connection -2. Bridge sends `{type: "qr", data: ""}` to GoClaw -3. GoClaw encodes as PNG and broadcasts via bus event -4. Web UI wizard displays the QR image -5. User scans with WhatsApp (You > Linked Devices > Link a Device) -6. Bridge confirms auth: `{type: "status", connected: true}` +1. GoClaw generates QR via whatsmeow's GetQRChannel() +2. QR string is encoded as PNG (base64) and sent to the UI wizard via WS event +3. Web UI displays the QR image +4. User scans with WhatsApp (You > Linked Devices > Link a Device) +5. whatsmeow confirms auth via Connected event -**Re-authentication**: Use the "Re-authenticate" button in the channels table to force a new QR scan (logs out the current WhatsApp session). +**Re-authentication**: Use the "Re-authenticate" button in the channels table to force a new QR scan (logs out the current WhatsApp session and deletes stored device credentials). ### DM and Group Policies @@ -124,17 +92,17 @@ Group `pairing` policy: unpaired groups receive a pairing code reply. Approve vi ### @Mention Gating -When `require_mention` is `true`, the bot only responds in group chats when explicitly @mentioned. Fails closed — if the bot's JID is unknown, messages are ignored. +When `require_mention` is `true`, the bot only responds in group chats when explicitly @mentioned. Unmentioned messages are recorded for context — when the bot is mentioned, recent group history is prepended to the message. -### Media Support +Fails closed — if the bot's JID is unknown, messages are ignored. -The bridge downloads incoming media (images, video, audio, documents, stickers) to a shared volume. GoClaw reads these files and passes them to the agent pipeline. +### Media Support -Supported inbound media types: image, video, audio, document, sticker. +GoClaw downloads incoming media directly via whatsmeow (images, video, audio, documents, stickers) to temporary files, then passes them to the agent pipeline. -Outbound media: GoClaw writes files to the shared volume and sends the path to the bridge for delivery. +Supported inbound media types: image, video, audio, document, sticker (max 20 MB each). -**Shared volume** (Docker): Both `goclaw` and `whatsapp-bridge` containers mount the same volume at `/tmp/goclaw_wa_media`. +Outbound media: GoClaw uploads files to WhatsApp's servers via whatsmeow with proper encryption. Supports image, video, audio, and document types with captions. ### Message Formatting @@ -145,12 +113,12 @@ LLM output is converted from Markdown to WhatsApp's native formatting: | `**bold**` | `*bold*` | **bold** | | `_italic_` | `_italic_` | _italic_ | | `~~strikethrough~~` | `~strikethrough~` | ~~strikethrough~~ | -| `` `inline code` `` | ` ```code``` ` | `code` | +| `` `inline code` `` | `` `inline code` `` | `code` | | `# Header` | `*Header*` | **Header** | | `[text](url)` | `text url` | text url | -| `- list item` | `* list item` | * list item | +| `- list item` | `• list item` | • list item | -Fenced code blocks are preserved as ` ``` `. HTML tags from LLM output are pre-processed to Markdown equivalents before conversion. +Fenced code blocks are preserved as ` ``` `. HTML tags from LLM output are pre-processed to Markdown equivalents before conversion. Long messages are automatically chunked at ~4096 characters, splitting at paragraph or line boundaries. ### Typing Indicators @@ -158,69 +126,38 @@ GoClaw shows "typing..." in WhatsApp while the agent processes a message. WhatsA ### Auto-Reconnect -If the bridge connection drops: -- Exponential backoff: 1s > 2s > 4s > ... > 30s max -- Continuous retry until bridge is available -- Channel health status updated (degraded/healthy) - -## Bridge Protocol - -### Bridge > GoClaw - -| Type | Payload | Description | -|------|---------|-------------| -| `status` | `{connected: bool, me: "jid"}` | Auth state (sent on connect + change) | -| `qr` | `{data: "qr-string"}` | QR code for scanning | -| `message` | `{id, from, chat, content, from_name, is_group, mentioned_jids, media}` | Incoming message | -| `pong` | `{}` | Response to ping | - -### GoClaw > Bridge - -| Type | Payload | Description | -|------|---------|-------------| -| `message` | `{to: "jid", content: "text"}` | Send outbound text | -| `command` | `{action: "reauth"}` | Logout + restart QR flow | -| `command` | `{action: "ping"}` | Health check | -| `command` | `{action: "presence", to, state}` | Presence (composing/paused) | - -## Docker Compose - -The `docker-compose.whatsapp.yml` overlay adds the bridge service: - -```yaml -services: - whatsapp-bridge: - build: ./bridge/whatsapp - ports: - - "3001:3001" - volumes: - - wa_auth:/app/auth_info # Persistent auth state - - wa_media:/tmp/goclaw_wa_media # Shared media volume - environment: - - BRIDGE_PORT=3001 - - PRINT_QR=false - - goclaw: - volumes: - - wa_media:/tmp/goclaw_wa_media # Same media volume - -volumes: - wa_auth: - wa_media: -``` +whatsmeow handles reconnection automatically. If the connection drops: +- whatsmeow's built-in reconnect logic handles retry +- Channel health status updated (degraded → healthy on reconnect) +- No manual reconnect loop needed + +### LID Addressing + +WhatsApp uses dual identity: phone JID (`@s.whatsapp.net`) and LID (`@lid`). Groups may use LID addressing. GoClaw normalizes to phone JID for consistent policy checks, pairing lookups, and allowlists. ## Troubleshooting | Issue | Solution | |-------|----------| -| "Connection refused" | Verify bridge is running and `bridge_url` is correct. For Docker, use `ws://whatsapp-bridge:3001`. | -| No QR code appears | Check bridge logs. Ensure the bridge can reach WhatsApp servers. Try `PRINT_QR=true` for terminal QR. | -| QR scanned but no auth | Auth state may be corrupted. Delete `auth_info/` directory and restart bridge. | -| Messages not received | Check bridge protocol: must send `type:"message"` with `from`/`content` fields (not `sender`/`body`). | -| Media not received | Ensure shared volume is mounted in both containers. Check `MEDIA_MAX_BYTES` limit. | -| "Bridge format mismatch" warning | Your bridge sends messages without a `type` field. Add `type:"message"` and use `from`/`content` field names. | -| Typing indicator stuck | GoClaw auto-cancels typing when reply is sent. If stuck, the bridge connection may have dropped. | +| No QR code appears | Check GoClaw logs. Ensure the server can reach WhatsApp servers (ports 443, 5222). | +| QR scanned but no auth | Auth state may be corrupted. Use "Re-authenticate" button or restart the channel. | +| Messages not received | Check `dm_policy` and `group_policy`. If `pairing`, the user/group needs approval via `goclaw pairing approve`. | +| Media not received | Check GoClaw logs for "media download failed". Ensure temp directory is writable. Max 20 MB per file. | +| Typing indicator stuck | GoClaw auto-cancels typing when reply is sent. If stuck, WhatsApp connection may have dropped — check channel health. | | Group messages ignored | Check `group_policy`. If `pairing`, the group needs approval. If `require_mention` is true, @mention the bot. | +| "logged out" in logs | WhatsApp revoked the session. Use "Re-authenticate" button to scan a new QR code. | +| `bridge_url` error on startup | `bridge_url` is no longer supported. WhatsApp now runs natively — remove `bridge_url` from config/credentials. | + +## Migrating from Bridge + +If you previously used the Baileys bridge (`bridge_url` config): + +1. Remove `bridge_url` from your channel config or credentials +2. Remove/stop the bridge container (no longer needed) +3. Delete the bridge shared volume (`wa_media`) +4. Re-authenticate via QR scan in the UI (existing bridge auth state is not compatible) + +GoClaw will detect old `bridge_url` config and show a clear migration error. ## What's Next @@ -229,4 +166,4 @@ volumes: - [Larksuite](/channel-feishu) — Larksuite integration - [Browser Pairing](/channel-browser-pairing) — Pairing flow - + diff --git a/vi/channels/INDEX.md b/vi/channels/INDEX.md index feb94bb..e7dd428 100644 --- a/vi/channels/INDEX.md +++ b/vi/channels/INDEX.md @@ -11,7 +11,7 @@ Tài liệu đầy đủ cho tất cả các tích hợp nền tảng nhắn tin 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook, streaming cards, media 6. **[Zalo OA](./zalo-oa.md)** — Official Account, chỉ DM, pairing, hình ảnh 7. **[Zalo Cá nhân](./zalo-personal.md)** — Tài khoản cá nhân (không chính thức), DM + nhóm -8. **[WhatsApp](./whatsapp.md)** — Baileys bridge, xác thực QR, media, typing indicators, pairing +8. **[WhatsApp](./whatsapp.md)** — Native (whatsmeow), xác thực QR, media, typing indicators, pairing 9. **[WebSocket](./websocket.md)** — RPC trực tiếp, custom client, streaming events 10. **[Ghép nối trình duyệt](./browser-pairing.md)** — Xác thực mã 8 ký tự, session token @@ -20,7 +20,7 @@ Tài liệu đầy đủ cho tất cả các tích hợp nền tảng nhắn tin | Tính năng | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo CN | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| | **Độ phức tạp** | Dễ | Dễ | Dễ | Trung bình | Trung bình | Khó | Trung bình | Rất dễ | -| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Baileys Bridge | WebSocket | +| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Native (whatsmeow) | WebSocket | | **Hỗ trợ DM** | Có | Có | Có | Có | Có | Có | Có | N/A | | **Hỗ trợ nhóm** | Có | Có | Có | Có | Không | Có | Có | N/A | | **Streaming** | Có | Có | Có | Có | Không | Không | Không | Có | diff --git a/vi/channels/whatsapp.md b/vi/channels/whatsapp.md index 558c01d..c923e99 100644 --- a/vi/channels/whatsapp.md +++ b/vi/channels/whatsapp.md @@ -2,44 +2,16 @@ # Channel WhatsApp -Tích hợp WhatsApp qua bridge WebSocket dựa trên Baileys. GoClaw kết nối như WS client đến bridge, bridge xử lý giao thức multi-device của WhatsApp (không cần Chrome). +Tích hợp WhatsApp gốc qua [whatsmeow](https://github.com/tulir/whatsmeow). GoClaw kết nối trực tiếp đến giao thức multi-device của WhatsApp — không cần bridge hay dịch vụ Node.js bên ngoài. Trạng thái xác thực được lưu trong database (PostgreSQL hoặc SQLite). ## Thiết lập -### Bắt đầu nhanh (Docker Compose) - -Cách nhanh nhất để chạy WhatsApp là dùng Docker Compose overlay đi kèm: - -```bash -docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.whatsapp.yml up -d -``` - -Sau đó trong giao diện GoClaw: 1. **Channels > Add Channel > WhatsApp** -2. Đặt **Bridge URL** thành `ws://whatsapp-bridge:3001` -3. Chọn agent, bấm **Create & Scan QR** -4. Quét QR bằng WhatsApp (Bạn > Thiết bị liên kết > Liên kết thiết bị) - -### Chạy Bridge thủ công - -Nếu bạn muốn chạy bridge ngoài Docker: - -```bash -cd bridge/whatsapp -npm install -node server.js -``` - -Biến môi trường: +2. Chọn agent, bấm **Create & Scan QR** +3. Quét QR bằng WhatsApp (Bạn > Thiết bị liên kết > Liên kết thiết bị) +4. Cấu hình chính sách DM/nhóm theo nhu cầu -| Biến | Mặc định | Mô tả | -|------|---------|-------| -| `BRIDGE_PORT` | `3001` | Cổng WebSocket server | -| `AUTH_DIR` | `./auth_info` | Thư mục lưu trạng thái xác thực WhatsApp | -| `MEDIA_DIR` | Thư mục temp hệ thống | Thư mục lưu media tải về | -| `MEDIA_MAX_BYTES` | `20971520` (20 MB) | Kích thước media tối đa | -| `LOG_LEVEL` | `silent` | Mức log bridge (`silent`, `warn`) | -| `PRINT_QR` | `false` | In QR code ra terminal (hữu ích khi không có UI) | +Vậy là xong — không cần triển khai bridge, không cần container phụ. ### Cấu hình qua file config @@ -50,7 +22,6 @@ Cho channel cấu hình qua file (thay vì DB instance): "channels": { "whatsapp": { "enabled": true, - "bridge_url": "ws://localhost:3001", "dm_policy": "pairing", "group_policy": "pairing" } @@ -65,11 +36,11 @@ Tất cả config key nằm trong `channels.whatsapp` (file config) hoặc confi | Key | Kiểu | Mặc định | Mô tả | |-----|------|---------|-------| | `enabled` | bool | `false` | Bật/tắt channel | -| `bridge_url` | string | bắt buộc | URL WebSocket đến bridge (ví dụ: `ws://bridge:3001`) | | `allow_from` | list | -- | Danh sách trắng user/group ID | | `dm_policy` | string | `"pairing"` | `pairing`, `open`, `allowlist`, `disabled` | | `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | `pairing`, `open`, `allowlist`, `disabled` | | `require_mention` | bool | `false` | Chỉ trả lời trong nhóm khi bot được @mention | +| `history_limit` | int | `200` | Số tin nhắn nhóm tối đa cho ngữ cảnh (0=tắt) | | `block_reply` | bool | -- | Ghi đè block_reply của gateway (nil=kế thừa) | ## Kiến trúc @@ -77,19 +48,17 @@ Tất cả config key nằm trong `channels.whatsapp` (file config) hoặc confi ```mermaid flowchart LR WA["WhatsApp
Servers"] - BRIDGE["Baileys Bridge
(Node.js WS Server)"] - GC["GoClaw
(WS Client)"] + GC["GoClaw
(whatsmeow)"] UI["Web UI
(QR Wizard)"] - WA <-->|"Giao thức multi-device"| BRIDGE - BRIDGE <-->|"JSON qua WebSocket"| GC - GC -->|"QR event qua WS bus"| UI + WA <-->|"Giao thức multi-device"| GC + GC -->|"QR event qua WS"| UI ``` -- **Bridge** là WebSocket **server** (mặc định cổng 3001) -- **GoClaw** kết nối như **client** và xử lý routing, AI, pairing -- Một bridge instance = một số điện thoại WhatsApp -- File media được trao đổi qua shared volume (`/tmp/goclaw_wa_media`) +- **GoClaw** kết nối trực tiếp đến WhatsApp server qua whatsmeow (thư viện Go) +- Trạng thái xác thực lưu trong database — tồn tại qua khởi động lại +- Một channel instance = một số điện thoại WhatsApp +- Không bridge, không Node.js, không shared volume ## Tính năng @@ -97,14 +66,13 @@ flowchart LR WhatsApp yêu cầu quét QR để liên kết thiết bị. Quy trình: -1. Bridge tạo QR qua kết nối Baileys -2. Bridge gửi `{type: "qr", data: ""}` đến GoClaw -3. GoClaw mã hóa thành PNG và broadcast qua bus event -4. Web UI wizard hiển thị ảnh QR -5. Người dùng quét bằng WhatsApp (Bạn > Thiết bị liên kết > Liên kết thiết bị) -6. Bridge xác nhận xác thực: `{type: "status", connected: true}` +1. GoClaw tạo QR qua GetQRChannel() của whatsmeow +2. Chuỗi QR được mã hóa thành PNG (base64) và gửi đến UI wizard qua WS event +3. Web UI hiển thị ảnh QR +4. Người dùng quét bằng WhatsApp (Bạn > Thiết bị liên kết > Liên kết thiết bị) +5. whatsmeow xác nhận xác thực qua Connected event -**Xác thực lại**: Dùng nút "Re-authenticate" trong bảng channels để buộc quét QR mới (đăng xuất phiên WhatsApp hiện tại). +**Xác thực lại**: Dùng nút "Re-authenticate" trong bảng channels để buộc quét QR mới (đăng xuất phiên WhatsApp hiện tại và xóa thông tin thiết bị đã lưu). ### Chính sách DM và Nhóm @@ -126,17 +94,17 @@ Chính sách `pairing` cho nhóm: nhóm chưa ghép nối nhận mã pairing. Ph ### @Mention Gating -Khi `require_mention` là `true`, bot chỉ trả lời trong nhóm khi được @mention trực tiếp. Fail-closed — nếu JID của bot chưa xác định, tin nhắn sẽ bị bỏ qua. +Khi `require_mention` là `true`, bot chỉ trả lời trong nhóm khi được @mention trực tiếp. Tin nhắn không mention được ghi lại cho ngữ cảnh — khi bot được mention, lịch sử nhóm gần đây được thêm vào đầu tin nhắn. -### Hỗ trợ Media +Fail-closed — nếu JID của bot chưa xác định, tin nhắn sẽ bị bỏ qua. -Bridge tải media đến (ảnh, video, audio, tài liệu, sticker) vào shared volume. GoClaw đọc các file này và chuyển vào pipeline agent. +### Hỗ trợ Media -Loại media đến được hỗ trợ: image, video, audio, document, sticker. +GoClaw tải media đến trực tiếp qua whatsmeow (ảnh, video, audio, tài liệu, sticker) vào file tạm, sau đó chuyển vào pipeline agent. -Media đi: GoClaw ghi file vào shared volume và gửi đường dẫn đến bridge để gửi đi. +Loại media đến được hỗ trợ: image, video, audio, document, sticker (tối đa 20 MB mỗi file). -**Shared volume** (Docker): Cả container `goclaw` và `whatsapp-bridge` mount cùng volume tại `/tmp/goclaw_wa_media`. +Media đi: GoClaw upload file lên server WhatsApp qua whatsmeow với mã hóa phù hợp. Hỗ trợ image, video, audio và document kèm caption. ### Định dạng tin nhắn @@ -147,12 +115,12 @@ Output LLM được chuyển đổi từ Markdown sang định dạng native c | `**bold**` | `*bold*` | **bold** | | `_italic_` | `_italic_` | _italic_ | | `~~strikethrough~~` | `~strikethrough~` | ~~strikethrough~~ | -| `` `inline code` `` | ` ```code``` ` | `code` | +| `` `inline code` `` | `` `inline code` `` | `code` | | `# Header` | `*Header*` | **Header** | | `[text](url)` | `text url` | text url | -| `- list item` | `* list item` | * list item | +| `- list item` | `• list item` | • list item | -Fenced code block được giữ nguyên dạng ` ``` `. Tag HTML từ output LLM được tiền xử lý thành Markdown trước khi chuyển đổi. +Fenced code block được giữ nguyên dạng ` ``` `. Tag HTML từ output LLM được tiền xử lý thành Markdown trước khi chuyển đổi. Tin nhắn dài tự động được chia nhỏ tại ~4096 ký tự, tách ở ranh giới đoạn hoặc dòng. ### Chỉ báo đang nhập @@ -160,69 +128,38 @@ GoClaw hiển thị "đang nhập..." trong WhatsApp khi agent xử lý tin nh ### Tự động kết nối lại -Nếu kết nối bridge bị đứt: -- Exponential backoff: 1s > 2s > 4s > ... > tối đa 30s -- Thử lại liên tục cho đến khi bridge khả dụng -- Trạng thái sức khỏe channel được cập nhật (degraded/healthy) - -## Giao thức Bridge - -### Bridge > GoClaw - -| Loại | Payload | Mô tả | -|------|---------|-------| -| `status` | `{connected: bool, me: "jid"}` | Trạng thái xác thực (gửi khi kết nối + thay đổi) | -| `qr` | `{data: "qr-string"}` | QR code để quét | -| `message` | `{id, from, chat, content, from_name, is_group, mentioned_jids, media}` | Tin nhắn đến | -| `pong` | `{}` | Phản hồi ping | - -### GoClaw > Bridge - -| Loại | Payload | Mô tả | -|------|---------|-------| -| `message` | `{to: "jid", content: "text"}` | Gửi tin nhắn | -| `command` | `{action: "reauth"}` | Đăng xuất + khởi động lại QR | -| `command` | `{action: "ping"}` | Kiểm tra sức khỏe | -| `command` | `{action: "presence", to, state}` | Presence (composing/paused) | - -## Docker Compose - -File `docker-compose.whatsapp.yml` overlay thêm dịch vụ bridge: - -```yaml -services: - whatsapp-bridge: - build: ./bridge/whatsapp - ports: - - "3001:3001" - volumes: - - wa_auth:/app/auth_info # Trạng thái xác thực bền vững - - wa_media:/tmp/goclaw_wa_media # Shared media volume - environment: - - BRIDGE_PORT=3001 - - PRINT_QR=false - - goclaw: - volumes: - - wa_media:/tmp/goclaw_wa_media # Cùng media volume - -volumes: - wa_auth: - wa_media: -``` +whatsmeow tự xử lý kết nối lại. Nếu kết nối bị đứt: +- Logic reconnect tích hợp của whatsmeow xử lý retry +- Trạng thái sức khỏe channel được cập nhật (degraded → healthy khi kết nối lại) +- Không cần vòng lặp reconnect thủ công + +### Địa chỉ LID + +WhatsApp dùng định danh kép: phone JID (`@s.whatsapp.net`) và LID (`@lid`). Nhóm có thể dùng địa chỉ LID. GoClaw chuẩn hóa về phone JID để kiểm tra chính sách, tra cứu pairing và allowlist nhất quán. ## Xử lý sự cố | Vấn đề | Giải pháp | |--------|----------| -| "Connection refused" | Xác minh bridge đang chạy và `bridge_url` đúng. Với Docker, dùng `ws://whatsapp-bridge:3001`. | -| Không hiển thị QR | Kiểm tra log bridge. Đảm bảo bridge kết nối được WhatsApp server. Thử `PRINT_QR=true` để hiện QR trong terminal. | -| Quét QR nhưng không xác thực | Trạng thái xác thực có thể bị hỏng. Xóa thư mục `auth_info/` và khởi động lại bridge. | -| Không nhận tin nhắn | Kiểm tra giao thức bridge: phải gửi `type:"message"` với field `from`/`content` (không phải `sender`/`body`). | -| Không nhận media | Đảm bảo shared volume được mount trong cả hai container. Kiểm tra giới hạn `MEDIA_MAX_BYTES`. | -| Cảnh báo "Bridge format mismatch" | Bridge gửi tin nhắn thiếu field `type`. Thêm `type:"message"` và dùng tên field `from`/`content`. | -| Chỉ báo đang nhập bị kẹt | GoClaw tự hủy typing khi gửi trả lời. Nếu bị kẹt, kết nối bridge có thể đã đứt. | +| Không hiển thị QR | Kiểm tra log GoClaw. Đảm bảo server kết nối được WhatsApp server (port 443, 5222). | +| Quét QR nhưng không xác thực | Trạng thái xác thực có thể bị hỏng. Dùng nút "Re-authenticate" hoặc khởi động lại channel. | +| Không nhận tin nhắn | Kiểm tra `dm_policy` và `group_policy`. Nếu là `pairing`, user/nhóm cần phê duyệt qua `goclaw pairing approve`. | +| Không nhận media | Kiểm tra log GoClaw tìm "media download failed". Đảm bảo thư mục temp ghi được. Tối đa 20 MB mỗi file. | +| Chỉ báo đang nhập bị kẹt | GoClaw tự hủy typing khi gửi trả lời. Nếu bị kẹt, kết nối WhatsApp có thể đã đứt — kiểm tra health channel. | | Tin nhắn nhóm bị bỏ qua | Kiểm tra `group_policy`. Nếu là `pairing`, nhóm cần phê duyệt. Nếu `require_mention` là true, @mention bot. | +| "logged out" trong log | WhatsApp đã thu hồi phiên. Dùng nút "Re-authenticate" để quét QR mới. | +| Lỗi `bridge_url` khi khởi động | `bridge_url` không còn được hỗ trợ. WhatsApp giờ chạy native — xóa `bridge_url` khỏi config/credentials. | + +## Di chuyển từ Bridge + +Nếu trước đây bạn dùng Baileys bridge (config `bridge_url`): + +1. Xóa `bridge_url` khỏi config hoặc credentials channel +2. Xóa/dừng container bridge (không cần nữa) +3. Xóa shared volume bridge (`wa_media`) +4. Xác thực lại qua quét QR trong UI (trạng thái xác thực bridge cũ không tương thích) + +GoClaw sẽ phát hiện config `bridge_url` cũ và hiển thị lỗi di chuyển rõ ràng. ## Tiếp theo @@ -231,4 +168,4 @@ volumes: - [Larksuite](/channel-feishu) — Tích hợp Larksuite - [Browser Pairing](/channel-browser-pairing) — Luồng pairing - + diff --git a/zh/channels/INDEX.md b/zh/channels/INDEX.md index c6839f9..f54d822 100644 --- a/zh/channels/INDEX.md +++ b/zh/channels/INDEX.md @@ -13,7 +13,7 @@ GoClaw 所有消息平台集成的完整文档。 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook、流式卡片、媒体 6. **[Zalo OA](./zalo-oa.md)** — 官方账号、仅 DM、配对、图片 7. **[Zalo 个人](./zalo-personal.md)** — 个人账号(非官方)、DM + 群组 -8. **[WhatsApp](./whatsapp.md)** — Baileys 桥接、QR 认证、媒体、输入指示器、配对 +8. **[WhatsApp](./whatsapp.md)** — 原生(whatsmeow)、QR 认证、媒体、输入指示器、配对 9. **[WebSocket](./websocket.md)** — 直接 RPC、自定义客户端、流式事件 10. **[Browser Pairing](./browser-pairing.md)** — 8 位码认证、session token @@ -22,7 +22,7 @@ GoClaw 所有消息平台集成的完整文档。 | 功能 | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo 个人 | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| | **设置复杂度** | 简单 | 简单 | 简单 | 中等 | 中等 | 困难 | 中等 | 非常简单 | -| **传输方式** | 轮询 | Gateway | Socket Mode | WS/Webhook | 轮询 | 协议 | Baileys 桥接 | WebSocket | +| **传输方式** | 轮询 | Gateway | Socket Mode | WS/Webhook | 轮询 | 协议 | 原生(whatsmeow) | WebSocket | | **DM 支持** | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 无 | | **群组支持** | 是 | 是 | 是 | 是 | 否 | 是 | 是 | 无 | | **流式输出** | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 是 | @@ -144,9 +144,7 @@ GoClaw 所有消息平台集成的完整文档。 ### WhatsApp -- [ ] 部署桥接:`docker compose -f docker-compose.whatsapp.yml up -d`(或 `cd bridge/whatsapp && npm install && node server.js`) - [ ] 在 UI 中创建 channel:Channels > Add Channel > WhatsApp -- [ ] 设置 Bridge URL(如 `ws://whatsapp-bridge:3001`) - [ ] 用 WhatsApp 扫描 QR 码(你 > 已关联的设备 > 关联设备) - [ ] 根据需要配置 DM/群组策略 diff --git a/zh/channels/whatsapp.md b/zh/channels/whatsapp.md index 0c9d3b5..4d761b1 100644 --- a/zh/channels/whatsapp.md +++ b/zh/channels/whatsapp.md @@ -2,44 +2,16 @@ # WhatsApp Channel -通过基于 Baileys 的外部 WebSocket 桥接集成 WhatsApp。GoClaw 作为 WS 客户端连接到桥接,桥接处理 WhatsApp 多设备协议(无需 Chrome)。 +通过 [whatsmeow](https://github.com/tulir/whatsmeow) 原生集成 WhatsApp。GoClaw 直接连接 WhatsApp 多设备协议 —— 无需外部桥接或 Node.js 服务。认证状态存储在数据库中(PostgreSQL 或 SQLite)。 ## 设置 -### 快速开始(Docker Compose) - -最快的方式是使用自带的 Docker Compose overlay: - -```bash -docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.whatsapp.yml up -d -``` - -然后在 GoClaw 界面中: 1. **Channels > Add Channel > WhatsApp** -2. 将 **Bridge URL** 设为 `ws://whatsapp-bridge:3001` -3. 选择 agent,点击 **Create & Scan QR** -4. 用 WhatsApp 扫描 QR 码(你 > 已关联的设备 > 关联设备) - -### 手动运行桥接 - -如果您想在 Docker 外运行桥接: - -```bash -cd bridge/whatsapp -npm install -node server.js -``` - -环境变量: +2. 选择 agent,点击 **Create & Scan QR** +3. 用 WhatsApp 扫描 QR 码(你 > 已关联的设备 > 关联设备) +4. 按需配置 DM/群组策略 -| 变量 | 默认值 | 说明 | -|------|--------|------| -| `BRIDGE_PORT` | `3001` | WebSocket 服务端口 | -| `AUTH_DIR` | `./auth_info` | WhatsApp 认证状态存储目录 | -| `MEDIA_DIR` | 系统临时目录 | 下载媒体文件存储目录 | -| `MEDIA_MAX_BYTES` | `20971520`(20 MB) | 最大媒体下载大小 | -| `LOG_LEVEL` | `silent` | 桥接日志级别(`silent`、`warn`) | -| `PRINT_QR` | `false` | 在终端打印 QR 码(无 UI 时有用) | +就这么简单 —— 无需部署桥接,无需额外容器。 ### 配置文件设置 @@ -50,7 +22,6 @@ node server.js "channels": { "whatsapp": { "enabled": true, - "bridge_url": "ws://localhost:3001", "dm_policy": "pairing", "group_policy": "pairing" } @@ -65,11 +36,11 @@ node server.js | 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | `enabled` | bool | `false` | 启用/禁用 channel | -| `bridge_url` | string | 必填 | 到桥接的 WebSocket URL(如 `ws://bridge:3001`) | | `allow_from` | list | -- | 用户/群组 ID 白名单 | | `dm_policy` | string | `"pairing"` | `pairing`、`open`、`allowlist`、`disabled` | | `group_policy` | string | `"pairing"`(DB)/ `"open"`(配置) | `pairing`、`open`、`allowlist`、`disabled` | | `require_mention` | bool | `false` | 仅在群组中被 @提及时回复 | +| `history_limit` | int | `200` | 群组上下文最大待处理消息数(0=禁用) | | `block_reply` | bool | -- | 覆盖 gateway block_reply(nil=继承) | ## 架构 @@ -77,19 +48,17 @@ node server.js ```mermaid flowchart LR WA["WhatsApp
服务器"] - BRIDGE["Baileys 桥接
(Node.js WS Server)"] - GC["GoClaw
(WS Client)"] + GC["GoClaw
(whatsmeow)"] UI["Web UI
(QR 向导)"] - WA <-->|"多设备协议"| BRIDGE - BRIDGE <-->|"WebSocket JSON"| GC - GC -->|"QR 事件通过 WS bus"| UI + WA <-->|"多设备协议"| GC + GC -->|"QR 事件通过 WS"| UI ``` -- **桥接**是 WebSocket **服务器**(默认端口 3001) -- **GoClaw** 作为**客户端**连接,处理路由、AI、配对 -- 一个桥接实例 = 一个 WhatsApp 手机号 -- 媒体文件通过共享卷交换(`/tmp/goclaw_wa_media`) +- **GoClaw** 通过 whatsmeow(Go 库)直接连接 WhatsApp 服务器 +- 认证状态存储在数据库 —— 重启后保留 +- 一个 channel 实例 = 一个 WhatsApp 手机号 +- 无桥接、无 Node.js、无共享卷 ## 功能特性 @@ -97,14 +66,13 @@ flowchart LR WhatsApp 需要扫描 QR 码来关联设备。流程: -1. 桥接通过 Baileys 连接生成 QR -2. 桥接发送 `{type: "qr", data: ""}` 给 GoClaw -3. GoClaw 编码为 PNG 并通过 bus 事件广播 -4. Web UI 向导显示 QR 图片 -5. 用户用 WhatsApp 扫描(你 > 已关联的设备 > 关联设备) -6. 桥接确认认证:`{type: "status", connected: true}` +1. GoClaw 通过 whatsmeow 的 GetQRChannel() 生成 QR +2. QR 字符串编码为 PNG(base64)并通过 WS 事件发送到 UI 向导 +3. Web UI 显示 QR 图片 +4. 用户用 WhatsApp 扫描(你 > 已关联的设备 > 关联设备) +5. whatsmeow 通过 Connected 事件确认认证 -**重新认证**:在 channels 表中点击"Re-authenticate"按钮强制新 QR 扫描(登出当前 WhatsApp 会话)。 +**重新认证**:在 channels 表中点击"Re-authenticate"按钮强制新 QR 扫描(登出当前 WhatsApp 会话并删除已存储的设备凭据)。 ### DM 和群组策略 @@ -126,17 +94,17 @@ WhatsApp 群组的 chat ID 以 `@g.us` 结尾: ### @提及过滤 -当 `require_mention` 为 `true` 时,机器人仅在群聊中被明确 @提及时才回复。失败关闭 —— 如果机器人的 JID 未知,消息将被忽略。 +当 `require_mention` 为 `true` 时,机器人仅在群聊中被明确 @提及时才回复。未提及的消息会被记录用于上下文 —— 当机器人被提及时,近期群组历史会被添加到消息前面。 -### 媒体支持 +失败关闭 —— 如果机器人的 JID 未知,消息将被忽略。 -桥接将收到的媒体(图片、视频、音频、文档、贴纸)下载到共享卷。GoClaw 读取这些文件并传入 agent 管道。 +### 媒体支持 -支持的入站媒体类型:image、video、audio、document、sticker。 +GoClaw 通过 whatsmeow 直接下载收到的媒体(图片、视频、音频、文档、贴纸)到临时文件,然后传入 agent 管道。 -出站媒体:GoClaw 将文件写入共享卷,发送路径给桥接进行投递。 +支持的入站媒体类型:image、video、audio、document、sticker(每个最大 20 MB)。 -**共享卷**(Docker):`goclaw` 和 `whatsapp-bridge` 容器都挂载同一卷到 `/tmp/goclaw_wa_media`。 +出站媒体:GoClaw 通过 whatsmeow 将文件上传到 WhatsApp 服务器并进行适当加密。支持带标题的 image、video、audio 和 document 类型。 ### 消息格式化 @@ -147,12 +115,12 @@ LLM 输出从 Markdown 转换为 WhatsApp 原生格式: | `**bold**` | `*bold*` | **bold** | | `_italic_` | `_italic_` | _italic_ | | `~~strikethrough~~` | `~strikethrough~` | ~~strikethrough~~ | -| `` `inline code` `` | ` ```code``` ` | `code` | +| `` `inline code` `` | `` `inline code` `` | `code` | | `# Header` | `*Header*` | **Header** | | `[text](url)` | `text url` | text url | -| `- list item` | `* list item` | * list item | +| `- list item` | `• list item` | • list item | -围栏代码块保持为 ` ``` `。来自 LLM 输出的 HTML 标签在转换前预处理为 Markdown 等效形式。 +围栏代码块保持为 ` ``` `。来自 LLM 输出的 HTML 标签在转换前预处理为 Markdown 等效形式。长消息自动在约 4096 个字符处分割,在段落或行边界处断开。 ### 输入指示器 @@ -160,69 +128,38 @@ GoClaw 在 agent 处理消息时在 WhatsApp 中显示"正在输入..."。WhatsA ### 自动重连 -若桥接连接断开: -- 指数退避:1s > 2s > 4s > ... > 最大 30s -- 持续重试直到桥接可用 -- Channel 健康状态更新(degraded/healthy) - -## 桥接协议 - -### 桥接 > GoClaw - -| 类型 | 负载 | 说明 | -|------|------|------| -| `status` | `{connected: bool, me: "jid"}` | 认证状态(连接时和变更时发送) | -| `qr` | `{data: "qr-string"}` | 用于扫描的 QR 码 | -| `message` | `{id, from, chat, content, from_name, is_group, mentioned_jids, media}` | 收到的消息 | -| `pong` | `{}` | ping 的响应 | - -### GoClaw > 桥接 - -| 类型 | 负载 | 说明 | -|------|------|------| -| `message` | `{to: "jid", content: "text"}` | 发送消息 | -| `command` | `{action: "reauth"}` | 登出 + 重启 QR 流程 | -| `command` | `{action: "ping"}` | 健康检查 | -| `command` | `{action: "presence", to, state}` | 在线状态(composing/paused) | - -## Docker Compose - -`docker-compose.whatsapp.yml` overlay 添加桥接服务: - -```yaml -services: - whatsapp-bridge: - build: ./bridge/whatsapp - ports: - - "3001:3001" - volumes: - - wa_auth:/app/auth_info # 持久化认证状态 - - wa_media:/tmp/goclaw_wa_media # 共享媒体卷 - environment: - - BRIDGE_PORT=3001 - - PRINT_QR=false - - goclaw: - volumes: - - wa_media:/tmp/goclaw_wa_media # 同一媒体卷 - -volumes: - wa_auth: - wa_media: -``` +whatsmeow 自动处理重连。如果连接断开: +- whatsmeow 内置的重连逻辑处理重试 +- Channel 健康状态更新(degraded → healthy 重连后) +- 无需手动重连循环 + +### LID 寻址 + +WhatsApp 使用双重身份:phone JID(`@s.whatsapp.net`)和 LID(`@lid`)。群组可能使用 LID 寻址。GoClaw 标准化为 phone JID 以确保策略检查、配对查找和白名单的一致性。 ## 故障排查 | 问题 | 解决方案 | |------|----------| -| "Connection refused" | 验证桥接正在运行且 `bridge_url` 正确。Docker 环境使用 `ws://whatsapp-bridge:3001`。 | -| 不显示 QR 码 | 检查桥接日志。确保桥接能连接 WhatsApp 服务器。尝试 `PRINT_QR=true` 在终端显示 QR。 | -| 扫描 QR 但未认证 | 认证状态可能损坏。删除 `auth_info/` 目录并重启桥接。 | -| 未收到消息 | 检查桥接协议:必须发送 `type:"message"` 且包含 `from`/`content` 字段(不是 `sender`/`body`)。 | -| 未收到媒体 | 确保两个容器都挂载了共享卷。检查 `MEDIA_MAX_BYTES` 限制。 | -| "Bridge format mismatch" 警告 | 桥接发送的消息缺少 `type` 字段。添加 `type:"message"` 并使用 `from`/`content` 字段名。 | -| 输入指示器卡住 | GoClaw 在发送回复时自动取消 typing。如果卡住,桥接连接可能已断开。 | +| 不显示 QR 码 | 检查 GoClaw 日志。确保服务器能连接 WhatsApp 服务器(端口 443、5222)。 | +| 扫描 QR 但未认证 | 认证状态可能损坏。使用"Re-authenticate"按钮或重启 channel。 | +| 未收到消息 | 检查 `dm_policy` 和 `group_policy`。如果是 `pairing`,用户/群组需要通过 `goclaw pairing approve` 审批。 | +| 未收到媒体 | 检查 GoClaw 日志中的"media download failed"。确保临时目录可写。每个文件最大 20 MB。 | +| 输入指示器卡住 | GoClaw 在发送回复时自动取消 typing。如果卡住,WhatsApp 连接可能已断开 —— 检查 channel 健康状态。 | | 群组消息被忽略 | 检查 `group_policy`。如果是 `pairing`,群组需要审批。如果 `require_mention` 为 true,@提及机器人。 | +| 日志中出现"logged out" | WhatsApp 撤销了会话。使用"Re-authenticate"按钮扫描新 QR 码。 | +| 启动时 `bridge_url` 错误 | `bridge_url` 已不再支持。WhatsApp 现在原生运行 —— 从 config/credentials 中删除 `bridge_url`。 | + +## 从桥接迁移 + +如果您之前使用 Baileys 桥接(`bridge_url` 配置): + +1. 从 channel 配置或凭据中删除 `bridge_url` +2. 删除/停止桥接容器(不再需要) +3. 删除桥接共享卷(`wa_media`) +4. 在 UI 中通过 QR 扫描重新认证(桥接的认证状态不兼容) + +GoClaw 会检测旧的 `bridge_url` 配置并显示清晰的迁移错误。 ## 下一步 @@ -231,4 +168,4 @@ volumes: - [Larksuite](/channel-feishu) — Larksuite 集成 - [Browser Pairing](/channel-browser-pairing) — 配对流程 - + From f861b4bdfeec750f933108542ee092a8da64d9b4 Mon Sep 17 00:00:00 2001 From: Duc Nguyen Date: Tue, 7 Apr 2026 00:05:19 +0700 Subject: [PATCH 3/4] docs(whatsapp): remove bridge references from config, troubleshooting, env vars - configuration.md: replace bridge_url with new config fields (require_mention, history_limit) - config-reference.md: expand WhatsApp table with full field list - environment-variables.md: replace BRIDGE_URL with ENABLED - troubleshooting/channels.md: rewrite WhatsApp section for native connection - All 3 locales updated (en, vi, zh) --- getting-started/configuration.md | 14 ++++++++------ reference/config-reference.md | 7 ++++++- reference/environment-variables.md | 2 +- troubleshooting/channels.md | 20 ++++++++++---------- vi/getting-started/configuration.md | 14 ++++++++------ vi/reference/config-reference.md | 7 ++++++- vi/reference/environment-variables.md | 2 +- vi/troubleshooting/channels.md | 20 ++++++++++---------- zh/getting-started/configuration.md | 7 +++++-- zh/reference/config-reference.md | 7 ++++++- zh/reference/environment-variables.md | 2 +- zh/troubleshooting/channels.md | 20 ++++++++++---------- 12 files changed, 72 insertions(+), 50 deletions(-) diff --git a/getting-started/configuration.md b/getting-started/configuration.md index 444b2d9..3278918 100644 --- a/getting-started/configuration.md +++ b/getting-started/configuration.md @@ -572,20 +572,22 @@ Docker-based isolation for code execution. Can be set globally or overridden per ```jsonc "whatsapp": { "enabled": true, - "bridge_url": "http://localhost:8080", "allow_from": [], - "dm_policy": "open", - "group_policy": "disabled", + "dm_policy": "pairing", + "group_policy": "pairing", + "require_mention": false, + "history_limit": 200, "block_reply": false } ``` | Field | Type | Default | Description | |-------|------|---------|-------------| -| `bridge_url` | string | — | WhatsApp bridge service URL | | `allow_from` | []string | — | Allowlisted phone numbers/JIDs | -| `dm_policy` | string | `"open"` | DM access policy | -| `group_policy` | string | `"disabled"` | Group access policy | +| `dm_policy` | string | `"pairing"` | DM access policy | +| `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | Group access policy | +| `require_mention` | bool | `false` | Only respond in groups when @mentioned | +| `history_limit` | int | `200` | Max pending group messages for context | | `block_reply` | bool | `false` | Suppress intermediate replies | ### Zalo diff --git a/reference/config-reference.md b/reference/config-reference.md index 47249ff..1636c45 100644 --- a/reference/config-reference.md +++ b/reference/config-reference.md @@ -272,7 +272,12 @@ Messaging channel configuration. | Field | Type | Default | Description | |-------|------|---------|-------------| | `enabled` | boolean | `false` | Enable WhatsApp channel | -| `bridge_url` | string | — | WhatsApp bridge service URL | +| `allow_from` | string[] | — | Allowlist of user/group JIDs | +| `dm_policy` | string | `"pairing"` | `"pairing"`, `"open"`, `"allowlist"`, `"disabled"` | +| `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | `"open"`, `"pairing"`, `"allowlist"`, `"disabled"` | +| `require_mention` | boolean | `false` | Only respond in groups when @mentioned | +| `history_limit` | int | `200` | Max pending group messages for context (0=disabled) | +| `block_reply` | boolean | — | Override gateway block_reply (nil=inherit) | ### `channels.slack` diff --git a/reference/environment-variables.md b/reference/environment-variables.md index aa7c977..e54c9e8 100644 --- a/reference/environment-variables.md +++ b/reference/environment-variables.md @@ -101,7 +101,7 @@ Setting a token/credential via environment auto-enables that channel. | `GOCLAW_LARK_APP_SECRET` | Feishu/Lark | App secret | | `GOCLAW_LARK_ENCRYPT_KEY` | Feishu/Lark | Event encryption key | | `GOCLAW_LARK_VERIFICATION_TOKEN` | Feishu/Lark | Event verification token | -| `GOCLAW_WHATSAPP_BRIDGE_URL` | WhatsApp | Bridge service URL | +| `GOCLAW_WHATSAPP_ENABLED` | WhatsApp | Enable WhatsApp channel (`true`/`false`) | --- diff --git a/troubleshooting/channels.md b/troubleshooting/channels.md index 9ed7aae..e1141b6 100644 --- a/troubleshooting/channels.md +++ b/troubleshooting/channels.md @@ -95,19 +95,19 @@ Zalo OA Bot is **DM only** (no group chats) with a 2000-character text limit per ## WhatsApp -WhatsApp uses a **bridge pattern** — GoClaw connects to an external bridge (e.g., mautrix-whatsapp) over WebSocket. GoClaw does not connect directly to WhatsApp. +WhatsApp connects **directly** via native multi-device protocol. No external bridge service required. Auth state is stored in the database (PostgreSQL/SQLite). | Problem | Cause | Solution | |---------|-------|----------| -| `whatsapp bridge_url is required` | Bridge URL not set | Set `GOCLAW_WHATSAPP_BRIDGE_URL` | -| `dial whatsapp bridge ...: ...` | Bridge not running or wrong URL | Start your bridge service; verify URL and port | -| `initial whatsapp bridge connection failed, will retry` | Bridge not ready yet | Transient — GoClaw retries automatically | -| `whatsapp bridge not connected` on send | Message attempted before bridge connected | Wait for bridge startup; check logs for reconnect messages | -| `invalid whatsapp message JSON` | Bridge version mismatch | Update bridge to expected message format | - -**Required env var:** `GOCLAW_WHATSAPP_BRIDGE_URL=ws://localhost:29318` - -The bridge must be separately authenticated with WhatsApp (QR scan via bridge UI) before GoClaw can send/receive messages. +| No QR code appears | Server can't reach WhatsApp | Check network connectivity (ports 443, 5222) | +| QR scanned but no auth | Auth state corrupted | Use "Re-authenticate" in UI or restart channel | +| `whatsapp bridge_url is required` | Old config still present | Remove `bridge_url` from config/credentials — no longer needed | +| `whatsapp not connected` on send | Not yet authenticated | Scan QR code via UI wizard first | +| `logged out` in logs | WhatsApp revoked session | Use "Re-authenticate" button to scan new QR | +| Group messages ignored | Policy or mention gate | Check `group_policy` and `require_mention` settings | +| Media download failed | Network or file issue | Check logs; verify temp dir writable; max 20 MB per file | + +Authentication is done via QR scan in the GoClaw UI (Channels > WhatsApp > Re-authenticate). --- diff --git a/vi/getting-started/configuration.md b/vi/getting-started/configuration.md index b17a73b..8ef033f 100644 --- a/vi/getting-started/configuration.md +++ b/vi/getting-started/configuration.md @@ -574,20 +574,22 @@ Cô lập dựa trên Docker cho thực thi code. Có thể đặt toàn cục h ```jsonc "whatsapp": { "enabled": true, - "bridge_url": "http://localhost:8080", "allow_from": [], - "dm_policy": "open", - "group_policy": "disabled", + "dm_policy": "pairing", + "group_policy": "pairing", + "require_mention": false, + "history_limit": 200, "block_reply": false } ``` | Trường | Kiểu | Mặc định | Mô tả | |--------|------|---------|-------| -| `bridge_url` | string | — | URL dịch vụ bridge WhatsApp | | `allow_from` | []string | — | Số điện thoại/JID được phép | -| `dm_policy` | string | `"open"` | Chính sách truy cập DM | -| `group_policy` | string | `"disabled"` | Chính sách truy cập nhóm | +| `dm_policy` | string | `"pairing"` | Chính sách truy cập DM | +| `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | Chính sách truy cập nhóm | +| `require_mention` | bool | `false` | Chỉ trả lời trong nhóm khi được @mention | +| `history_limit` | int | `200` | Số tin nhắn nhóm tối đa cho ngữ cảnh (0=tắt) | | `block_reply` | bool | `false` | Ẩn các phản hồi trung gian | ### Zalo diff --git a/vi/reference/config-reference.md b/vi/reference/config-reference.md index 4fe16fd..3cc63a8 100644 --- a/vi/reference/config-reference.md +++ b/vi/reference/config-reference.md @@ -274,7 +274,12 @@ Cấu hình messaging channel. | Field | Type | Mặc định | Mô tả | |-------|------|----------|-------| | `enabled` | boolean | `false` | Bật WhatsApp channel | -| `bridge_url` | string | — | URL WhatsApp bridge service | +| `allow_from` | string[] | — | Danh sách trắng user/group JID | +| `dm_policy` | string | `"pairing"` | `"pairing"`, `"open"`, `"allowlist"`, `"disabled"` | +| `group_policy` | string | `"pairing"` (DB) / `"open"` (config) | `"open"`, `"pairing"`, `"allowlist"`, `"disabled"` | +| `require_mention` | boolean | `false` | Chỉ trả lời trong nhóm khi được @mention | +| `history_limit` | int | `200` | Số tin nhắn nhóm tối đa cho ngữ cảnh (0=tắt) | +| `block_reply` | boolean | — | Ghi đè gateway block_reply (nil=kế thừa) | ### `channels.slack` diff --git a/vi/reference/environment-variables.md b/vi/reference/environment-variables.md index c4f8d83..76a449b 100644 --- a/vi/reference/environment-variables.md +++ b/vi/reference/environment-variables.md @@ -103,7 +103,7 @@ API key từ environment ghi đè mọi giá trị trong `config.json`. Đặt k | `GOCLAW_LARK_APP_SECRET` | Feishu/Lark | App secret | | `GOCLAW_LARK_ENCRYPT_KEY` | Feishu/Lark | Encryption key cho event | | `GOCLAW_LARK_VERIFICATION_TOKEN` | Feishu/Lark | Verification token cho event | -| `GOCLAW_WHATSAPP_BRIDGE_URL` | WhatsApp | URL bridge service | +| `GOCLAW_WHATSAPP_ENABLED` | WhatsApp | Bật WhatsApp channel (`true`/`false`) | --- diff --git a/vi/troubleshooting/channels.md b/vi/troubleshooting/channels.md index 821c64b..950237b 100644 --- a/vi/troubleshooting/channels.md +++ b/vi/troubleshooting/channels.md @@ -97,19 +97,19 @@ Zalo OA Bot **chỉ DM** (không có group chat) với giới hạn 2000 ký t ## WhatsApp -WhatsApp dùng **bridge pattern** — GoClaw kết nối với bridge bên ngoài (ví dụ mautrix-whatsapp) qua WebSocket. GoClaw không kết nối trực tiếp với WhatsApp. +WhatsApp **kết nối trực tiếp** (native multi-device protocol). Không cần bridge service bên ngoài. Trạng thái xác thực lưu trong database. | Vấn đề | Nguyên nhân | Cách xử lý | |--------|-------------|------------| -| `whatsapp bridge_url is required` | Bridge URL chưa đặt | Đặt `GOCLAW_WHATSAPP_BRIDGE_URL` | -| `dial whatsapp bridge ...: ...` | Bridge không chạy hoặc URL sai | Khởi động bridge service; xác minh URL và port | -| `initial whatsapp bridge connection failed, will retry` | Bridge chưa sẵn sàng | Tạm thời — GoClaw tự retry | -| `whatsapp bridge not connected` khi gửi | Tin nhắn được gửi trước khi bridge kết nối | Chờ bridge khởi động; kiểm tra log tìm reconnect message | -| `invalid whatsapp message JSON` | Bridge version mismatch | Cập nhật bridge theo đúng định dạng tin nhắn | - -**Env var bắt buộc:** `GOCLAW_WHATSAPP_BRIDGE_URL=ws://localhost:29318` - -Bridge phải được xác thực riêng với WhatsApp (QR scan qua bridge UI) trước khi GoClaw có thể gửi/nhận tin nhắn. +| Không hiển thị QR | Không kết nối được WhatsApp server | Kiểm tra mạng (port 443, 5222) | +| Quét QR nhưng không xác thực | Trạng thái xác thực bị hỏng | Dùng nút Re-authenticate hoặc restart channel | +| `whatsapp bridge_url is required` | Cấu hình cũ còn | Xóa bridge_url khỏi config — không còn cần | +| Gửi `whatsapp not connected` | Chưa xác thực | Scan QR qua UI wizard trước | +| Log hiện `logged out` | WhatsApp thu hồi phiên | Dùng nút Re-authenticate scan QR mới | +| Tin nhắn nhóm bị bỏ qua | Chính sách hoặc mention gate | Kiểm tra group_policy và require_mention | +| Media download thất bại | Mạng hoặc file | Kiểm tra log; xác nhận temp dir ghi được; tối đa 20 MB/file | + +Xác thực qua GoClaw UI (Channels > WhatsApp > Re-authenticate). --- diff --git a/zh/getting-started/configuration.md b/zh/getting-started/configuration.md index bc4cdb7..c39688a 100644 --- a/zh/getting-started/configuration.md +++ b/zh/getting-started/configuration.md @@ -496,9 +496,12 @@ GoClaw 使用 `fsnotify` 监控 `config.json` 的变化,带 300ms 防抖。Age ```jsonc "whatsapp": { "enabled": true, - "bridge_url": "http://localhost:8080", "allow_from": [], - "dm_policy": "open" + "dm_policy": "pairing", + "group_policy": "pairing", + "require_mention": false, + "history_limit": 200, + "block_reply": false } ``` diff --git a/zh/reference/config-reference.md b/zh/reference/config-reference.md index 894ac39..1a3f5f2 100644 --- a/zh/reference/config-reference.md +++ b/zh/reference/config-reference.md @@ -274,7 +274,12 @@ Agent evolution 设置存储在 agent 的 `other_config` JSONB 字段中(通 | 字段 | 类型 | 默认值 | 说明 | |-------|------|---------|-------------| | `enabled` | boolean | `false` | 启用 WhatsApp channel | -| `bridge_url` | string | — | WhatsApp 桥接服务 URL | +| `allow_from` | string[] | — | 用户/群组 JID 白名单 | +| `dm_policy` | string | `"pairing"` | `"pairing"`、`"open"`、`"allowlist"`、`"disabled"` | +| `group_policy` | string | `"pairing"`(DB)/ `"open"`(配置) | `"open"`、`"pairing"`、`"allowlist"`、`"disabled"` | +| `require_mention` | boolean | `false` | 仅在群组中被 @提及时回复 | +| `history_limit` | int | `200` | 群组上下文最大待处理消息数(0=禁用) | +| `block_reply` | boolean | — | 覆盖 gateway block_reply(nil=继承) | ### `channels.slack` diff --git a/zh/reference/environment-variables.md b/zh/reference/environment-variables.md index b9e90f7..bcc85bf 100644 --- a/zh/reference/environment-variables.md +++ b/zh/reference/environment-variables.md @@ -103,7 +103,7 @@ GOCLAW_POSTGRES_DSN="postgres://..." GOCLAW_GATEWAY_TOKEN="..." ./goclaw | `GOCLAW_LARK_APP_SECRET` | Feishu/Lark | App secret | | `GOCLAW_LARK_ENCRYPT_KEY` | Feishu/Lark | 事件加密密钥 | | `GOCLAW_LARK_VERIFICATION_TOKEN` | Feishu/Lark | 事件验证 token | -| `GOCLAW_WHATSAPP_BRIDGE_URL` | WhatsApp | 桥接服务 URL | +| `GOCLAW_WHATSAPP_ENABLED` | WhatsApp | 启用 WhatsApp channel(`true`/`false`) | --- diff --git a/zh/troubleshooting/channels.md b/zh/troubleshooting/channels.md index e86dfe3..f0d1b56 100644 --- a/zh/troubleshooting/channels.md +++ b/zh/troubleshooting/channels.md @@ -97,19 +97,19 @@ Zalo OA Bot **仅支持私信**(不支持群聊),每条消息文本限制 ## WhatsApp -WhatsApp 使用**桥接模式**——GoClaw 通过 WebSocket 连接到外部桥接(如 mautrix-whatsapp)。GoClaw 不直接连接到 WhatsApp。 +WhatsApp **直接连接**(原生多设备协议)。无需外部桥接服务。认证状态存储在数据库中。 | 问题 | 原因 | 解决方案 | |---------|-------|----------| -| `whatsapp bridge_url is required` | 未设置桥接 URL | 设置 `GOCLAW_WHATSAPP_BRIDGE_URL` | -| `dial whatsapp bridge ...: ...` | 桥接未运行或 URL 错误 | 启动桥接服务;验证 URL 和端口 | -| `initial whatsapp bridge connection failed, will retry` | 桥接尚未就绪 | 短暂性——GoClaw 自动重试 | -| 发送时 `whatsapp bridge not connected` | 桥接连接前尝试发送消息 | 等待桥接启动;检查日志中的重连消息 | -| `invalid whatsapp message JSON` | 桥接版本不匹配 | 将桥接更新到预期的消息格式 | - -**必填环境变量:** `GOCLAW_WHATSAPP_BRIDGE_URL=ws://localhost:29318` - -桥接必须与 WhatsApp 单独完成认证(通过桥接 UI 扫描二维码),GoClaw 才能发送/接收消息。 +| 没有显示 QR 码 | 无法连接 WhatsApp 服务器 | 检查网络(端口 443、5222) | +| 扫描 QR 但未认证 | 认证状态损坏 | 使用"重新认证"按钮或重启 channel | +| `whatsapp bridge_url is required` | 旧配置仍在 | 删除配置中的 `bridge_url` —— 不再需要 | +| 发送时 `whatsapp not connected` | 未认证 | 先通过 UI 向导扫描 QR 码 | +| 日志中出现 `logged out` | WhatsApp 撤销了会话 | 使用"重新认证"按钮扫描新 QR 码 | +| 群组消息被忽略 | 策略或 @提及 限制 | 检查 `group_policy` 和 `require_mention` 设置 | +| 媒体下载失败 | 网络或文件问题 | 检查日志;确认临时目录可写;每个文件最大 20 MB | + +通过 GoClaw UI 进行认证(Channels > WhatsApp > Re-authenticate)。 --- From 410f5465b95247787869ce45d2873a9de504fb71 Mon Sep 17 00:00:00 2001 From: Duc Nguyen Date: Tue, 7 Apr 2026 00:36:05 +0700 Subject: [PATCH 4/4] docs(whatsapp): remove library references, use generic "direct connection" wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace "Native (whatsmeow)" with "Direct connection" across all 3 locales (INDEX.md + whatsapp.md). Remove implementation-specific library details from user-facing docs — library names belong in code comments, not documentation. --- channels/INDEX.md | 4 ++-- channels/whatsapp.md | 20 ++++++++++---------- vi/channels/INDEX.md | 4 ++-- vi/channels/whatsapp.md | 20 ++++++++++---------- zh/channels/INDEX.md | 4 ++-- zh/channels/whatsapp.md | 20 ++++++++++---------- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/channels/INDEX.md b/channels/INDEX.md index e94353b..aae6aca 100644 --- a/channels/INDEX.md +++ b/channels/INDEX.md @@ -11,7 +11,7 @@ Complete documentation for all messaging platform integrations in GoClaw. 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook, streaming cards, media 6. **[Zalo OA](./zalo-oa.md)** — Official Account, DM-only, pairing, images 7. **[Zalo Personal](./zalo-personal.md)** — Personal account (unofficial), DM + groups -8. **[WhatsApp](./whatsapp.md)** — Native (whatsmeow), QR auth, media, typing indicators, pairing +8. **[WhatsApp](./whatsapp.md)** — Direct connection, QR auth, media, typing indicators, pairing 9. **[WebSocket](./websocket.md)** — Direct RPC, custom clients, streaming events 10. **[Browser Pairing](./browser-pairing.md)** — 8-char code auth, session tokens @@ -20,7 +20,7 @@ Complete documentation for all messaging platform integrations in GoClaw. | Feature | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo Pers | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| | **Setup Complexity** | Easy | Easy | Easy | Medium | Medium | Hard | Medium | Very Easy | -| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Native (whatsmeow) | WebSocket | +| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Direct connection | WebSocket | | **DM Support** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | N/A | | **Group Support** | Yes | Yes | Yes | Yes | No | Yes | Yes | N/A | | **Streaming** | Yes | Yes | Yes | Yes | No | No | No | Yes | diff --git a/channels/whatsapp.md b/channels/whatsapp.md index 5d1438e..bb52ef5 100644 --- a/channels/whatsapp.md +++ b/channels/whatsapp.md @@ -1,6 +1,6 @@ # WhatsApp Channel -Native WhatsApp integration via [whatsmeow](https://github.com/tulir/whatsmeow). GoClaw connects directly to WhatsApp's multi-device protocol — no external bridge or Node.js service required. Auth state is stored in the database (PostgreSQL or SQLite). +Direct WhatsApp integration. GoClaw connects directly to WhatsApp's multi-device protocol — no external bridge or Node.js service required. Auth state is stored in the database (PostgreSQL or SQLite). ## Setup @@ -46,14 +46,14 @@ All config keys are in `channels.whatsapp` (config file) or the instance config ```mermaid flowchart LR WA["WhatsApp
Servers"] - GC["GoClaw
(whatsmeow)"] + GC["GoClaw"] UI["Web UI
(QR Wizard)"] WA <-->|"Multi-device protocol"| GC GC -->|"QR events via WS"| UI ``` -- **GoClaw** connects directly to WhatsApp servers via whatsmeow (Go library) +- **GoClaw** connects directly to WhatsApp servers via multi-device protocol - Auth state is stored in the database — survives restarts - One channel instance = one WhatsApp phone number - No bridge, no Node.js, no shared volumes @@ -64,11 +64,11 @@ flowchart LR WhatsApp requires QR code scanning to link a device. The flow: -1. GoClaw generates QR via whatsmeow's GetQRChannel() +1. GoClaw generates QR code for device linking 2. QR string is encoded as PNG (base64) and sent to the UI wizard via WS event 3. Web UI displays the QR image 4. User scans with WhatsApp (You > Linked Devices > Link a Device) -5. whatsmeow confirms auth via Connected event +5. Connection confirmed via auth event **Re-authentication**: Use the "Re-authenticate" button in the channels table to force a new QR scan (logs out the current WhatsApp session and deletes stored device credentials). @@ -98,11 +98,11 @@ Fails closed — if the bot's JID is unknown, messages are ignored. ### Media Support -GoClaw downloads incoming media directly via whatsmeow (images, video, audio, documents, stickers) to temporary files, then passes them to the agent pipeline. +GoClaw downloads incoming media directly (images, video, audio, documents, stickers) to temporary files, then passes them to the agent pipeline. Supported inbound media types: image, video, audio, document, sticker (max 20 MB each). -Outbound media: GoClaw uploads files to WhatsApp's servers via whatsmeow with proper encryption. Supports image, video, audio, and document types with captions. +Outbound media: GoClaw uploads files to WhatsApp's servers with proper encryption. Supports image, video, audio, and document types with captions. ### Message Formatting @@ -126,8 +126,8 @@ GoClaw shows "typing..." in WhatsApp while the agent processes a message. WhatsA ### Auto-Reconnect -whatsmeow handles reconnection automatically. If the connection drops: -- whatsmeow's built-in reconnect logic handles retry +Reconnection is handled automatically. If the connection drops: +- Built-in reconnect logic handles retry with exponential backoff - Channel health status updated (degraded → healthy on reconnect) - No manual reconnect loop needed @@ -166,4 +166,4 @@ GoClaw will detect old `bridge_url` config and show a clear migration error. - [Larksuite](/channel-feishu) — Larksuite integration - [Browser Pairing](/channel-browser-pairing) — Pairing flow - + diff --git a/vi/channels/INDEX.md b/vi/channels/INDEX.md index e7dd428..b58c54c 100644 --- a/vi/channels/INDEX.md +++ b/vi/channels/INDEX.md @@ -11,7 +11,7 @@ Tài liệu đầy đủ cho tất cả các tích hợp nền tảng nhắn tin 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook, streaming cards, media 6. **[Zalo OA](./zalo-oa.md)** — Official Account, chỉ DM, pairing, hình ảnh 7. **[Zalo Cá nhân](./zalo-personal.md)** — Tài khoản cá nhân (không chính thức), DM + nhóm -8. **[WhatsApp](./whatsapp.md)** — Native (whatsmeow), xác thực QR, media, typing indicators, pairing +8. **[WhatsApp](./whatsapp.md)** — Kết nối trực tiếp, xác thực QR, media, typing indicators, pairing 9. **[WebSocket](./websocket.md)** — RPC trực tiếp, custom client, streaming events 10. **[Ghép nối trình duyệt](./browser-pairing.md)** — Xác thực mã 8 ký tự, session token @@ -20,7 +20,7 @@ Tài liệu đầy đủ cho tất cả các tích hợp nền tảng nhắn tin | Tính năng | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo CN | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| | **Độ phức tạp** | Dễ | Dễ | Dễ | Trung bình | Trung bình | Khó | Trung bình | Rất dễ | -| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Native (whatsmeow) | WebSocket | +| **Transport** | Polling | Gateway | Socket Mode | WS/Webhook | Polling | Protocol | Kết nối trực tiếp | WebSocket | | **Hỗ trợ DM** | Có | Có | Có | Có | Có | Có | Có | N/A | | **Hỗ trợ nhóm** | Có | Có | Có | Có | Không | Có | Có | N/A | | **Streaming** | Có | Có | Có | Có | Không | Không | Không | Có | diff --git a/vi/channels/whatsapp.md b/vi/channels/whatsapp.md index c923e99..94aefa3 100644 --- a/vi/channels/whatsapp.md +++ b/vi/channels/whatsapp.md @@ -2,7 +2,7 @@ # Channel WhatsApp -Tích hợp WhatsApp gốc qua [whatsmeow](https://github.com/tulir/whatsmeow). GoClaw kết nối trực tiếp đến giao thức multi-device của WhatsApp — không cần bridge hay dịch vụ Node.js bên ngoài. Trạng thái xác thực được lưu trong database (PostgreSQL hoặc SQLite). +Tích hợp WhatsApp trực tiếp. GoClaw kết nối trực tiếp đến giao thức multi-device của WhatsApp — không cần bridge hay dịch vụ Node.js bên ngoài. Trạng thái xác thực được lưu trong database (PostgreSQL hoặc SQLite). ## Thiết lập @@ -48,14 +48,14 @@ Tất cả config key nằm trong `channels.whatsapp` (file config) hoặc confi ```mermaid flowchart LR WA["WhatsApp
Servers"] - GC["GoClaw
(whatsmeow)"] + GC["GoClaw"] UI["Web UI
(QR Wizard)"] WA <-->|"Giao thức multi-device"| GC GC -->|"QR event qua WS"| UI ``` -- **GoClaw** kết nối trực tiếp đến WhatsApp server qua whatsmeow (thư viện Go) +- **GoClaw** kết nối trực tiếp đến WhatsApp server qua giao thức multi-device - Trạng thái xác thực lưu trong database — tồn tại qua khởi động lại - Một channel instance = một số điện thoại WhatsApp - Không bridge, không Node.js, không shared volume @@ -66,11 +66,11 @@ flowchart LR WhatsApp yêu cầu quét QR để liên kết thiết bị. Quy trình: -1. GoClaw tạo QR qua GetQRChannel() của whatsmeow +1. GoClaw tạo mã QR để liên kết thiết bị 2. Chuỗi QR được mã hóa thành PNG (base64) và gửi đến UI wizard qua WS event 3. Web UI hiển thị ảnh QR 4. Người dùng quét bằng WhatsApp (Bạn > Thiết bị liên kết > Liên kết thiết bị) -5. whatsmeow xác nhận xác thực qua Connected event +5. Xác thực được xác nhận qua sự kiện kết nối **Xác thực lại**: Dùng nút "Re-authenticate" trong bảng channels để buộc quét QR mới (đăng xuất phiên WhatsApp hiện tại và xóa thông tin thiết bị đã lưu). @@ -100,11 +100,11 @@ Fail-closed — nếu JID của bot chưa xác định, tin nhắn sẽ bị b ### Hỗ trợ Media -GoClaw tải media đến trực tiếp qua whatsmeow (ảnh, video, audio, tài liệu, sticker) vào file tạm, sau đó chuyển vào pipeline agent. +GoClaw tải media đến trực tiếp (ảnh, video, audio, tài liệu, sticker) vào file tạm, sau đó chuyển vào pipeline agent. Loại media đến được hỗ trợ: image, video, audio, document, sticker (tối đa 20 MB mỗi file). -Media đi: GoClaw upload file lên server WhatsApp qua whatsmeow với mã hóa phù hợp. Hỗ trợ image, video, audio và document kèm caption. +Media đi: GoClaw upload file lên server WhatsApp với mã hóa phù hợp. Hỗ trợ image, video, audio và document kèm caption. ### Định dạng tin nhắn @@ -128,8 +128,8 @@ GoClaw hiển thị "đang nhập..." trong WhatsApp khi agent xử lý tin nh ### Tự động kết nối lại -whatsmeow tự xử lý kết nối lại. Nếu kết nối bị đứt: -- Logic reconnect tích hợp của whatsmeow xử lý retry +Tự động kết nối lại khi kết nối bị đứt: +- Logic reconnect tích hợp xử lý retry với exponential backoff - Trạng thái sức khỏe channel được cập nhật (degraded → healthy khi kết nối lại) - Không cần vòng lặp reconnect thủ công @@ -168,4 +168,4 @@ GoClaw sẽ phát hiện config `bridge_url` cũ và hiển thị lỗi di chuy - [Larksuite](/channel-feishu) — Tích hợp Larksuite - [Browser Pairing](/channel-browser-pairing) — Luồng pairing - + diff --git a/zh/channels/INDEX.md b/zh/channels/INDEX.md index f54d822..adcfa80 100644 --- a/zh/channels/INDEX.md +++ b/zh/channels/INDEX.md @@ -13,7 +13,7 @@ GoClaw 所有消息平台集成的完整文档。 5. **[Larksuite](./larksuite.md)** — WebSocket/Webhook、流式卡片、媒体 6. **[Zalo OA](./zalo-oa.md)** — 官方账号、仅 DM、配对、图片 7. **[Zalo 个人](./zalo-personal.md)** — 个人账号(非官方)、DM + 群组 -8. **[WhatsApp](./whatsapp.md)** — 原生(whatsmeow)、QR 认证、媒体、输入指示器、配对 +8. **[WhatsApp](./whatsapp.md)** — 直连、QR 认证、媒体、输入指示器、配对 9. **[WebSocket](./websocket.md)** — 直接 RPC、自定义客户端、流式事件 10. **[Browser Pairing](./browser-pairing.md)** — 8 位码认证、session token @@ -22,7 +22,7 @@ GoClaw 所有消息平台集成的完整文档。 | 功能 | Telegram | Discord | Slack | Larksuite | Zalo OA | Zalo 个人 | WhatsApp | WebSocket | |---------|----------|---------|-------|--------|---------|-----------|----------|-----------| | **设置复杂度** | 简单 | 简单 | 简单 | 中等 | 中等 | 困难 | 中等 | 非常简单 | -| **传输方式** | 轮询 | Gateway | Socket Mode | WS/Webhook | 轮询 | 协议 | 原生(whatsmeow) | WebSocket | +| **传输方式** | 轮询 | Gateway | Socket Mode | WS/Webhook | 轮询 | 协议 | 直连 | WebSocket | | **DM 支持** | 是 | 是 | 是 | 是 | 是 | 是 | 是 | 无 | | **群组支持** | 是 | 是 | 是 | 是 | 否 | 是 | 是 | 无 | | **流式输出** | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 是 | diff --git a/zh/channels/whatsapp.md b/zh/channels/whatsapp.md index 4d761b1..3bb2cea 100644 --- a/zh/channels/whatsapp.md +++ b/zh/channels/whatsapp.md @@ -2,7 +2,7 @@ # WhatsApp Channel -通过 [whatsmeow](https://github.com/tulir/whatsmeow) 原生集成 WhatsApp。GoClaw 直接连接 WhatsApp 多设备协议 —— 无需外部桥接或 Node.js 服务。认证状态存储在数据库中(PostgreSQL 或 SQLite)。 +直接集成 WhatsApp。GoClaw 直接连接 WhatsApp 多设备协议 —— 无需外部桥接或 Node.js 服务。认证状态存储在数据库中(PostgreSQL 或 SQLite)。 ## 设置 @@ -48,14 +48,14 @@ ```mermaid flowchart LR WA["WhatsApp
服务器"] - GC["GoClaw
(whatsmeow)"] + GC["GoClaw"] UI["Web UI
(QR 向导)"] WA <-->|"多设备协议"| GC GC -->|"QR 事件通过 WS"| UI ``` -- **GoClaw** 通过 whatsmeow(Go 库)直接连接 WhatsApp 服务器 +- **GoClaw** 通过多设备协议直接连接 WhatsApp 服务器 - 认证状态存储在数据库 —— 重启后保留 - 一个 channel 实例 = 一个 WhatsApp 手机号 - 无桥接、无 Node.js、无共享卷 @@ -66,11 +66,11 @@ flowchart LR WhatsApp 需要扫描 QR 码来关联设备。流程: -1. GoClaw 通过 whatsmeow 的 GetQRChannel() 生成 QR +1. GoClaw 生成 QR 码用于设备关联 2. QR 字符串编码为 PNG(base64)并通过 WS 事件发送到 UI 向导 3. Web UI 显示 QR 图片 4. 用户用 WhatsApp 扫描(你 > 已关联的设备 > 关联设备) -5. whatsmeow 通过 Connected 事件确认认证 +5. 连接事件确认认证成功 **重新认证**:在 channels 表中点击"Re-authenticate"按钮强制新 QR 扫描(登出当前 WhatsApp 会话并删除已存储的设备凭据)。 @@ -100,11 +100,11 @@ WhatsApp 群组的 chat ID 以 `@g.us` 结尾: ### 媒体支持 -GoClaw 通过 whatsmeow 直接下载收到的媒体(图片、视频、音频、文档、贴纸)到临时文件,然后传入 agent 管道。 +GoClaw 直接下载收到的媒体(图片、视频、音频、文档、贴纸)到临时文件,然后传入 agent 管道。 支持的入站媒体类型:image、video、audio、document、sticker(每个最大 20 MB)。 -出站媒体:GoClaw 通过 whatsmeow 将文件上传到 WhatsApp 服务器并进行适当加密。支持带标题的 image、video、audio 和 document 类型。 +出站媒体:GoClaw 将文件上传到 WhatsApp 服务器并进行适当加密。支持带标题的 image、video、audio 和 document 类型。 ### 消息格式化 @@ -128,8 +128,8 @@ GoClaw 在 agent 处理消息时在 WhatsApp 中显示"正在输入..."。WhatsA ### 自动重连 -whatsmeow 自动处理重连。如果连接断开: -- whatsmeow 内置的重连逻辑处理重试 +自动处理重连。如果连接断开: +- 内置重连逻辑处理重试 - Channel 健康状态更新(degraded → healthy 重连后) - 无需手动重连循环 @@ -168,4 +168,4 @@ GoClaw 会检测旧的 `bridge_url` 配置并显示清晰的迁移错误。 - [Larksuite](/channel-feishu) — Larksuite 集成 - [Browser Pairing](/channel-browser-pairing) — 配对流程 - +