diff --git a/channels/INDEX.md b/channels/INDEX.md
index c2c68ad..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)** — External bridge, JSON protocol, auto-reconnect
+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
@@ -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 | 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 |
-| **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,9 @@ Flexible format supporting:
### WhatsApp
-- [ ] Deploy WhatsApp bridge service (e.g., whatsapp-web.js)
-- [ ] Copy WebSocket URL
-- [ ] Enable in config
+- [ ] Create channel in UI: Channels > Add Channel > WhatsApp
+- [ ] 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..bb52ef5 100644
--- a/channels/whatsapp.md
+++ b/channels/whatsapp.md
@@ -1,36 +1,27 @@
# WhatsApp Channel
-WhatsApp integration via external WebSocket bridge. GoClaw connects to a bridge service (e.g., whatsapp-web.js) that handles the WhatsApp protocol.
+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
-**Prerequisites:**
-- Running WhatsApp bridge service (e.g., whatsapp-web.js)
-- Bridge URL accessible to GoClaw
+1. **Channels > Add Channel > WhatsApp**
+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
-**Start WhatsApp Bridge:**
+That's it — no bridge to deploy, no extra containers.
-Example using whatsapp-web.js:
+### Config File Setup
-```bash
-npm install -g whatsapp-web.js
-# Start bridge server on localhost:3001
-whatsapp-bridge --port 3001
-```
-
-Your bridge should expose a WebSocket endpoint (e.g., `ws://localhost:3001`).
-
-**Enable WhatsApp:**
+For config-file-based channels (instead of DB instances):
```json
{
"channels": {
"whatsapp": {
"enabled": true,
- "bridge_url": "ws://localhost:3001",
- "dm_policy": "open",
- "group_policy": "open",
- "allow_from": []
+ "dm_policy": "pairing",
+ "group_policy": "pairing"
}
}
}
@@ -38,104 +29,135 @@ 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 |
-| `bridge_url` | string | required | WebSocket URL to bridge (e.g., `ws://bridge:3001`) |
+| `enabled` | bool | `false` | Enable/disable channel |
| `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 |
+| `history_limit` | int | `200` | Max pending group messages for context (0=disabled) |
| `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"]
+ GC["GoClaw"]
+ 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"| GC
+ GC -->|"QR events via WS"| UI
```
-### DM and Group Support
+- **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
-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. 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. Connection confirmed via auth event
-### 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 and deletes stored device credentials).
-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. Unmentioned messages are recorded for context — when the bot is mentioned, recent group history is prepended to the message.
-```go
-manager.SendToChannel(ctx, "whatsapp", "1234567890@c.us", "Hello!")
-```
+Fails closed — if the bot's JID is unknown, messages are ignored.
-### Checking if Chat is a Group
+### Media Support
-```go
-isGroup := strings.HasSuffix(chatID, "@g.us")
-```
+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 with proper encryption. Supports image, video, audio, and document types with captions.
+
+### 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` `` | `` `inline 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. Long messages are automatically chunked at ~4096 characters, splitting at paragraph or line boundaries.
+
+### 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
+
+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
+
+### 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. 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. |
+| 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
@@ -144,4 +166,4 @@ isGroup := strings.HasSuffix(chatID, "@g.us")
- [Larksuite](/channel-feishu) — Larksuite integration
- [Browser Pairing](/channel-browser-pairing) — Pairing flow
-
+
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/channels/INDEX.md b/vi/channels/INDEX.md
index 704f988..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)** — External bridge, giao thức JSON, tự động kết nối lại
+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
@@ -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 | 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ó |
-| **Đị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..94aefa3 100644
--- a/vi/channels/whatsapp.md
+++ b/vi/channels/whatsapp.md
@@ -2,37 +2,28 @@
# 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 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
-**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
+1. **Channels > Add Channel > WhatsApp**
+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
-**Khởi động WhatsApp Bridge:**
+Vậy là xong — không cần triển khai bridge, không cần container phụ.
-Ví dụ dùng whatsapp-web.js:
+### Cấu hình qua file config
-```bash
-npm install -g whatsapp-web.js
-# Khởi động bridge server trên localhost:3001
-whatsapp-bridge --port 3001
-```
-
-Bridge của bạn cần expose một WebSocket endpoint (ví dụ: `ws://localhost:3001`).
-
-**Bật WhatsApp:**
+Cho channel cấu hình qua file (thay vì DB instance):
```json
{
"channels": {
"whatsapp": {
"enabled": true,
- "bridge_url": "ws://localhost:3001",
- "dm_policy": "open",
- "group_policy": "open",
- "allow_from": []
+ "dm_policy": "pairing",
+ "group_policy": "pairing"
}
}
}
@@ -40,104 +31,135 @@ 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 |
-| `bridge_url` | string | bắt buộc | URL WebSocket đến bridge (ví dụ: `ws://bridge:3001`) |
+|-----|------|---------|-------|
+| `enabled` | bool | `false` | Bật/tắt channel |
| `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 |
+| `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) |
-## 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"]
+ GC["GoClaw"]
+ 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"| GC
+ GC -->|"QR event qua WS"| UI
```
-### Hỗ trợ DM và Nhóm
+- **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
-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. 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. Xác thực được xác nhận qua sự kiện kết nối
-### Đị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 và xóa thông tin thiết bị đã lưu).
-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. 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.
-```go
-manager.SendToChannel(ctx, "whatsapp", "1234567890@c.us", "Hello!")
-```
+Fail-closed — nếu JID của bot chưa xác định, tin nhắn sẽ bị bỏ qua.
-### Kiểm tra xem Chat có phải Nhóm không
+### Hỗ trợ Media
-```go
-isGroup := strings.HasSuffix(chatID, "@g.us")
-```
+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 với mã hóa phù hợp. Hỗ trợ image, video, audio và document kèm caption.
+
+### Đị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` `` | `` `inline 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. 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
+
+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
+
+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
+
+### Đị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. 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. |
+|--------|----------|
+| 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
@@ -146,4 +168,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/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/channels/INDEX.md b/zh/channels/INDEX.md
index 701719f..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)** — 外部桥接、JSON 协议、自动重连
+8. **[WhatsApp](./whatsapp.md)** — 直连、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 | 轮询 | 协议 | 直连 | 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,9 @@ GoClaw 所有消息平台集成的完整文档。
### WhatsApp
-- [ ] 部署 WhatsApp 桥接服务(如 whatsapp-web.js)
-- [ ] 复制 WebSocket URL
-- [ ] 在配置中启用
+- [ ] 在 UI 中创建 channel:Channels > Add Channel > WhatsApp
+- [ ] 用 WhatsApp 扫描 QR 码(你 > 已关联的设备 > 关联设备)
+- [ ] 根据需要配置 DM/群组策略
### WebSocket
diff --git a/zh/channels/whatsapp.md b/zh/channels/whatsapp.md
index 31c6754..3bb2cea 100644
--- a/zh/channels/whatsapp.md
+++ b/zh/channels/whatsapp.md
@@ -2,37 +2,28 @@
# WhatsApp Channel
-通过外部 WebSocket 桥接集成 WhatsApp。GoClaw 连接到处理 WhatsApp 协议的桥接服务(如 whatsapp-web.js)。
+直接集成 WhatsApp。GoClaw 直接连接 WhatsApp 多设备协议 —— 无需外部桥接或 Node.js 服务。认证状态存储在数据库中(PostgreSQL 或 SQLite)。
## 设置
-**前置条件:**
-- 运行中的 WhatsApp 桥接服务(如 whatsapp-web.js)
-- GoClaw 可访问的桥接 URL
+1. **Channels > Add Channel > WhatsApp**
+2. 选择 agent,点击 **Create & Scan QR**
+3. 用 WhatsApp 扫描 QR 码(你 > 已关联的设备 > 关联设备)
+4. 按需配置 DM/群组策略
-**启动 WhatsApp 桥接:**
+就这么简单 —— 无需部署桥接,无需额外容器。
-以 whatsapp-web.js 为例:
+### 配置文件设置
-```bash
-npm install -g whatsapp-web.js
-# 在 localhost:3001 启动桥接服务器
-whatsapp-bridge --port 3001
-```
-
-桥接应暴露 WebSocket 端点(如 `ws://localhost:3001`)。
-
-**启用 WhatsApp:**
+通过配置文件(而非 DB 实例)设置 channel:
```json
{
"channels": {
"whatsapp": {
"enabled": true,
- "bridge_url": "ws://localhost:3001",
- "dm_policy": "open",
- "group_policy": "open",
- "allow_from": []
+ "dm_policy": "pairing",
+ "group_policy": "pairing"
}
}
}
@@ -40,104 +31,135 @@ whatsapp-bridge --port 3001
## 配置
-所有配置项位于 `channels.whatsapp`:
+所有配置项位于 `channels.whatsapp`(配置文件)或实例配置 JSON(DB):
| 配置项 | 类型 | 默认值 | 说明 |
-|-----|------|---------|-------------|
-| `enabled` | bool | false | 启用/禁用 channel |
-| `bridge_url` | string | 必填 | 到桥接的 WebSocket URL(如 `ws://bridge:3001`) |
+|--------|------|--------|------|
+| `enabled` | bool | `false` | 启用/禁用 channel |
| `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` | 仅在群组中被 @提及时回复 |
+| `history_limit` | int | `200` | 群组上下文最大待处理消息数(0=禁用) |
| `block_reply` | bool | -- | 覆盖 gateway block_reply(nil=继承) |
-## 功能特性
-
-### 桥接连接
-
-GoClaw 通过 WebSocket 连接到桥接,发送/接收 JSON 消息。
+## 架构
```mermaid
flowchart LR
- GC["GoClaw"]
- WS["WebSocket
连接"]
- BRIDGE["WhatsApp
桥接"]
WA["WhatsApp
服务器"]
+ GC["GoClaw"]
+ UI["Web UI
(QR 向导)"]
- GC -->|"JSON 消息"| WS
- WS -->|"JSON 消息"| BRIDGE
- BRIDGE -->|"WhatsApp 协议"| WA
- WA -->|"协议"| BRIDGE
- BRIDGE -->|"JSON 事件"| WS
- WS -->|"事件"| GC
+ WA <-->|"多设备协议"| GC
+ GC -->|"QR 事件通过 WS"| UI
```
-### DM 和群组支持
+- **GoClaw** 通过多设备协议直接连接 WhatsApp 服务器
+- 认证状态存储在数据库 —— 重启后保留
+- 一个 channel 实例 = 一个 WhatsApp 手机号
+- 无桥接、无 Node.js、无共享卷
-桥接通过 chat ID 后缀 `@g.us` 检测群聊:
+## 功能特性
-- **DM**:`"1234567890@c.us"`
-- **群组**:`"123-456@g.us"`
+### QR 码认证
-策略相应应用(DM 使用 DM 策略,群组使用群组策略)。
+WhatsApp 需要扫描 QR 码来关联设备。流程:
-在群聊中,消息包含 `[From:]` 标注和发送者的显示名,让 agent 能够区分参与者。
+1. GoClaw 生成 QR 码用于设备关联
+2. QR 字符串编码为 PNG(base64)并通过 WS 事件发送到 UI 向导
+3. Web UI 显示 QR 图片
+4. 用户用 WhatsApp 扫描(你 > 已关联的设备 > 关联设备)
+5. 连接事件确认认证成功
-### 消息格式
+**重新认证**:在 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` 时,机器人仅在群聊中被明确 @提及时才回复。未提及的消息会被记录用于上下文 —— 当机器人被提及时,近期群组历史会被添加到消息前面。
-```go
-manager.SendToChannel(ctx, "whatsapp", "1234567890@c.us", "Hello!")
-```
+失败关闭 —— 如果机器人的 JID 未知,消息将被忽略。
-### 检查是否为群组
+### 媒体支持
-```go
-isGroup := strings.HasSuffix(chatID, "@g.us")
-```
+GoClaw 直接下载收到的媒体(图片、视频、音频、文档、贴纸)到临时文件,然后传入 agent 管道。
+
+支持的入站媒体类型:image、video、audio、document、sticker(每个最大 20 MB)。
+
+出站媒体:GoClaw 将文件上传到 WhatsApp 服务器并进行适当加密。支持带标题的 image、video、audio 和 document 类型。
+
+### 消息格式化
+
+LLM 输出从 Markdown 转换为 WhatsApp 原生格式:
+
+| Markdown | WhatsApp | 显示效果 |
+|----------|----------|----------|
+| `**bold**` | `*bold*` | **bold** |
+| `_italic_` | `_italic_` | _italic_ |
+| `~~strikethrough~~` | `~strikethrough~` | ~~strikethrough~~ |
+| `` `inline code` `` | `` `inline code` `` | `code` |
+| `# Header` | `*Header*` | **Header** |
+| `[text](url)` | `text url` | text url |
+| `- list item` | `• list item` | • list item |
+
+围栏代码块保持为 ` ``` `。来自 LLM 输出的 HTML 标签在转换前预处理为 Markdown 等效形式。长消息自动在约 4096 个字符处分割,在段落或行边界处断开。
+
+### 输入指示器
+
+GoClaw 在 agent 处理消息时在 WhatsApp 中显示"正在输入..."。WhatsApp 在约 10 秒后清除指示器,因此 GoClaw 每 8 秒刷新一次直到回复发送。
+
+### 自动重连
+
+自动处理重连。如果连接断开:
+- 内置重连逻辑处理重试
+- Channel 健康状态更新(degraded → healthy 重连后)
+- 无需手动重连循环
+
+### LID 寻址
+
+WhatsApp 使用双重身份:phone JID(`@s.whatsapp.net`)和 LID(`@lid`)。群组可能使用 LID 寻址。GoClaw 标准化为 phone JID 以确保策略检查、配对查找和白名单的一致性。
## 故障排查
| 问题 | 解决方案 |
-|-------|----------|
-| "Connection refused" | 验证桥接是否运行。检查 `bridge_url` 是否正确且可访问。 |
-| "WebSocket: close normal closure" | 桥接已优雅关闭。重启桥接服务。 |
-| 持续重连尝试 | 桥接已关闭或不可达。检查桥接日志。 |
-| 未收到消息 | 验证桥接是否接收 WhatsApp 事件。检查桥接日志。 |
-| 群组检测失败 | 确保群组 chat ID 以 `@g.us` 结尾,DM 以 `@c.us` 结尾。 |
-| 媒体未发送 | 确保文件路径对桥接可访问。检查桥接是否支持媒体。 |
+|------|----------|
+| 不显示 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` 配置并显示清晰的迁移错误。
## 下一步
@@ -146,4 +168,4 @@ isGroup := strings.HasSuffix(chatID, "@g.us")
- [Larksuite](/channel-feishu) — Larksuite 集成
- [Browser Pairing](/channel-browser-pairing) — 配对流程
-
+
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)。
---