@agent-wechat/agent-wechat 0.16.0 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -170
- package/dist/index.js +1764 -7107
- package/openclaw.plugin.json +229 -16
- package/package.json +109 -18
package/README.md
CHANGED
|
@@ -1,200 +1,73 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OpenClaw WeChat channel
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The plugin uses the standalone native daemon. External mode connects by endpoint/token to an independently operated daemon, including a native server container; the Gateway needs neither `wx` nor Docker tools. Managed mode starts an owned local daemon and requires a separately installed `wx`. Plugin installation/startup never downloads or repairs a binary. Old container API configurations require explicit migration.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Once published, install the native beta with `openclaw plugins install @agent-wechat/agent-wechat@beta` or pin its exact version. The stable `latest` channel continues to select the old container plugin during the beta series.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Native external mode
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **A second screen** — WeChat login requires scanning a QR code with your phone camera. You'll need the QR code displayed on a screen separate from the phone running WeChat (e.g., a computer monitor, tablet, or another phone).
|
|
12
|
-
|
|
13
|
-
- **An agent-wechat server** — Either self-hosted via Docker or provided by someone else. You'll need the server URL and authentication token.
|
|
14
|
-
|
|
15
|
-
> **Note:** The agent-wechat container requires `SYS_PTRACE` and `seccomp=unconfined` (ptrace access to the WeChat desktop process). It cannot run in serverless or restricted container environments (AWS Fargate, Cloud Run, etc.) — use a VM or bare-metal Docker host.
|
|
16
|
-
|
|
17
|
-
## Setup
|
|
18
|
-
|
|
19
|
-
### 1. Start the agent-wechat Server
|
|
20
|
-
|
|
21
|
-
If you need to run the server yourself:
|
|
22
|
-
|
|
23
|
-
**Option A: CLI** (quickest for local use)
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm install -g @agent-wechat/cli
|
|
27
|
-
wx up
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**Option B: Docker Compose** (production / networked)
|
|
31
|
-
|
|
32
|
-
```yaml
|
|
33
|
-
services:
|
|
34
|
-
agent-wechat:
|
|
35
|
-
image: ghcr.io/thisnick/agent-wechat:latest
|
|
36
|
-
container_name: agent-wechat
|
|
37
|
-
security_opt:
|
|
38
|
-
- seccomp=unconfined
|
|
39
|
-
cap_add:
|
|
40
|
-
- SYS_PTRACE
|
|
41
|
-
ports:
|
|
42
|
-
- "6174:6174"
|
|
43
|
-
volumes:
|
|
44
|
-
- agent-wechat-data:/data
|
|
45
|
-
- agent-wechat-home:/home/wechat
|
|
46
|
-
- ~/.config/agent-wechat/token:/data/auth-token:ro
|
|
47
|
-
restart: unless-stopped
|
|
48
|
-
|
|
49
|
-
volumes:
|
|
50
|
-
agent-wechat-data:
|
|
51
|
-
agent-wechat-home:
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Generate a token before starting:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
mkdir -p ~/.config/agent-wechat
|
|
58
|
-
openssl rand -hex 32 > ~/.config/agent-wechat/token
|
|
59
|
-
chmod 600 ~/.config/agent-wechat/token
|
|
60
|
-
docker compose up -d
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
If running alongside OpenClaw on the same Docker network, set `serverUrl` to `http://agent-wechat:6174` in the channel config.
|
|
64
|
-
|
|
65
|
-
### 2. Install the extension
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
openclaw plugins install @agent-wechat/agent-wechat
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### 3. Configure the channel
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
# Uses defaults (localhost:6174, token from ~/.config/agent-wechat/token)
|
|
75
|
-
openclaw channels add --channel agent-wechat
|
|
76
|
-
|
|
77
|
-
# Override server URL and token
|
|
78
|
-
openclaw channels add --channel agent-wechat --url <url> --token <token>
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Or edit `~/.openclaw/openclaw.json` directly:
|
|
9
|
+
Configure plugin defaults under `plugins.entries.agent-wechat.config` (or the same `native` configuration in the channel):
|
|
82
10
|
|
|
83
11
|
```json
|
|
84
12
|
{
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
13
|
+
"native": {
|
|
14
|
+
"mode": "external",
|
|
15
|
+
"accountId": "example",
|
|
16
|
+
"endpoint": "http://127.0.0.1:6174",
|
|
17
|
+
"token": { "source": "env", "provider": "default", "id": "AGENT_WECHAT_TOKEN" },
|
|
18
|
+
"consumerStateDir": "/private/openclaw-native-consumer",
|
|
19
|
+
"readPolicy": "on_model_dispatch"
|
|
93
20
|
}
|
|
94
21
|
}
|
|
95
22
|
```
|
|
96
23
|
|
|
97
|
-
|
|
24
|
+
The external service remains independently owned. Plugin stop closes its stream and never stops/logs out the daemon or cancels its sends. Remote endpoints require verified HTTPS or an encrypted tunnel terminating at loopback. Set `AGENT_WECHAT_TOKEN` in the Gateway process environment, or use a configured OpenClaw secret provider. The plugin resolves `native.token` through the pinned OpenClaw SDK; `native.tokenFile` is removed. Tokens contain 32–1024 printable ASCII bytes without spaces. An explicit unresolved reference fails startup without falling back to another token. The API token needs read/media/send/login for the selected account, plus read-state only when automatic local read projection is enabled; do not grant admin solely to run the plugin. Normal sender/DM/group/mention policy remains in `channels.agent-wechat`; defaults remain closed.
|
|
98
25
|
|
|
99
|
-
|
|
26
|
+
## Native managed mode
|
|
100
27
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
Your bot should generate a QR code image. Alternatively, use the CLI:
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
openclaw channels login --channel agent-wechat
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"native": {
|
|
31
|
+
"mode": "managed",
|
|
32
|
+
"accountId": "example",
|
|
33
|
+
"executable": "/opt/agent-wechat/bin/wx",
|
|
34
|
+
"listen": "127.0.0.1:6174",
|
|
35
|
+
"dataDir": "/private/native-store",
|
|
36
|
+
"token": { "source": "env", "provider": "default", "id": "AGENT_WECHAT_TOKEN" },
|
|
37
|
+
"consumerStateDir": "/private/openclaw-native-consumer",
|
|
38
|
+
"readPolicy": "never"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
119
41
|
```
|
|
120
42
|
|
|
121
|
-
|
|
43
|
+
Provision the native executable and account registration separately. Omitting `executable` resolves `wx` once from absolute trusted PATH entries. The plugin supports the package's tested npm launcher layout by selecting its already installed checksum-verified ELF payload directly. It never invokes an installer or shell. Unknown wrappers/old container CLIs are rejected. Managed startup refuses an occupied port and requires authenticated readiness matching the owned child PID, store path, server identity and process generation; it never adopts or terminates another process. Stop sends a graceful termination to its own child with bounded escalation. An unexpected child/stream failure is reported; automatic process crash restart is not implemented in this increment.
|
|
122
44
|
|
|
123
|
-
|
|
45
|
+
Managed startup sends the resolved token through a private stdin pipe; it creates no token file and does not put the token in arguments or the daemon environment. A managed `serverConfig` must omit `tokenFile`. Reload/restart the Gateway to change credentials or secret-provider configuration.
|
|
124
46
|
|
|
125
|
-
|
|
47
|
+
Keep `dataDir` and `consumerStateDir` on separate explicit persistent mounts. The daemon owns official-format profile/sidecar data; the consumer directory holds private intake/deduplication/model-handoff/read receipts bound to server and account identities. Executable upgrades do not remove either. One configured OpenClaw account maps to one selected native daemon account in this increment, while the daemon itself supports independent account slots.
|
|
126
48
|
|
|
127
|
-
|
|
49
|
+
## Native messaging lifecycle and validation limits
|
|
128
50
|
|
|
129
|
-
|
|
51
|
+
The adapter consumes account-scoped SSE using bearer headers and decimal-string journal cursors. It persists custody before acknowledging a cursor; acknowledgement is independent of unread state. Only explicitly live, incoming, committed resources can enter the model. Supported images, short voice, video, files and eligible stickers pass through bounded media retrieval and hash verification into OpenClaw-managed storage. Pending media retains custody without model dispatch or a read receipt. Expired/unsupported attachments retain an explicit status; raw XML never becomes an attachment. Catch-up/import/raw pending sync batches, unknown origin and outgoing messages do not become automatic model inputs. Group admission uses structured exact self-mention facts; unknown metadata or displayed `@names` never satisfy a mention gate. Contacts and groups use their separate catalogs.
|
|
130
52
|
|
|
131
|
-
|
|
53
|
+
The prepared-run callback synchronously writes a bounded durable receipt for the exact selected new message IDs before a separate retryable read projection. Read CAS retries preserve the same sparse IDs and never widen to the largest ID or clear concurrent arrivals. `readPolicy: "never"` disables automatic reads. Crashes during an unconfirmed dispatch retain `needs_review`; the plugin does not automatically duplicate model turns or uncertain outgoing sends.
|
|
132
54
|
|
|
133
|
-
|
|
55
|
+
OpenClaw **2026.10.2** lacks `onPreparedAgentRunStart`, so its released public hooks provide a bounded compatibility path. Before dispatch, the adapter persists an immutable manifest binding the exact new message ID/version/content hash, policy hash, source and supplied asset hashes, and context roles. Text requires the exact current input and host-created message/account/session facts plus a matching `model_call_started`. Media additionally waits for the same run's `agent_end` snapshot and source-turn identity. Image bytes/MIME/length must match the frozen supplied representation; file/video/voice references must appear in the exact current body. Image count, model selection and reply delivery alone cannot mark a message read. Unknown, omitted, rewritten, merged or ambiguous inputs remain unconfirmed.
|
|
134
56
|
|
|
135
|
-
|
|
57
|
+
The compatibility path requires the operator's explicit host permission, `plugins.entries.agent-wechat.hooks.allowConversationAccess: true`. It observes only run IDs issued by this adapter and never enables that permission itself. Without the grant, or on an unsupported host, messages remain unread and status reports `handoffUnconfirmed`. The older `onAgentRunStart` also reports direct tools and early lifecycle phases and is never used as proof. `readPolicy: "never"` preserves the handoff receipt while disabling read projection. Late confirmed receipts retry their exact sparse reads independently of new SSE traffic.
|
|
136
58
|
|
|
137
|
-
|
|
59
|
+
Images exceeding the host's bounded representation, or formats requiring conversion, receive a separately stored JPEG still preview using the public SDK image processor. The original stays intact; both hashes are recorded and the model input labels the preview. Prepared images fit within 5 MiB and at most 1200 pixels per side (or a smaller configured limit). Files and videos can be supplied as available local references; this does not claim their contents were analyzed. Voice retains its verified file and includes configured transcription output or an explicit unavailable status. Pending, expired, unsupported and failed-integrity media never gains a read receipt from a placeholder.
|
|
138
60
|
|
|
139
|
-
-
|
|
61
|
+
Run `node scripts/native-model-smoke.mjs` and `node scripts/native-media-model-smoke.mjs` after installing workspace dependencies. They use the actual pinned Gateway, a local model and synthetic daemon/files. Checks cover current provider input, image hashes and prepared previews, reference/transcription delivery, exact sparse reads, lost-read-response/reopen recovery, duplicate prevention, omitted images on a text-only model, permission, never-read policy and group routing behavior. Transcription uses the real SDK with an explicitly configured local deterministic CLI; it does not test speech recognition accuracy. Concurrent text inputs were serialized into distinct model turns; merged-input refusal has unit coverage. These checks establish the prepared runtime boundary, not external provider acceptance, semantic analysis or consumption.
|
|
140
62
|
|
|
141
|
-
|
|
63
|
+
Native text/media sends retain daemon intent/job identity and caller idempotency. Text waits for accepted submission; media jobs preserve partial and uncertain outcomes rather than resending. Ordinary audio remains a file; only explicit `audioAsVoice` requests independently encoded voice. Sender/group/mention gates run before retrieval/transcription. Verified voice may use the configured OpenClaw transcription runtime after admission. Native QR login uses a durable daemon operation and authenticated PNG retrieval. Logout commits local inhibition before at most one authenticated native logout, reporting the remote outcome separately; saved-device revocation remains unverified. Explicitly confirmed forgetting removes local auth while retaining history; disconnect retains reusable trust.
|
|
142
64
|
|
|
143
|
-
|
|
65
|
+
## Optional Gateway facade
|
|
144
66
|
|
|
145
|
-
|
|
146
|
-
|-----|------|---------|-------------|
|
|
147
|
-
| `enabled` | boolean | `false` | Enable the WeChat channel |
|
|
148
|
-
| `serverUrl` | string | — | agent-wechat REST API URL |
|
|
149
|
-
| `token` | string | — | Auth token (auto-read from `~/.config/agent-wechat/token` for local setups) |
|
|
150
|
-
| `dmPolicy` | `"open" \| "allowlist" \| "disabled"` | `"disabled"` | Who can DM the bot |
|
|
151
|
-
| `allowFrom` | string[] | `[]` | DM senders and command owners: `wxid_...`, `"*"` for everyone, or `accessGroup:<name>`. With `dmPolicy: "open"`, use `["*"]` |
|
|
152
|
-
| `groupPolicy` | `"open" \| "allowlist" \| "disabled"` | `"disabled"` | Group message policy |
|
|
153
|
-
| `groupAllowFrom` | string[] | `[]` | Group senders who pass `allowlist` and may run commands in groups; falls back to `allowFrom` when empty |
|
|
154
|
-
| `groups` | object | `{}` | Per-group overrides (e.g. `{ "id@chatroom": { "requireMention": false, "enabled": true, "groupPolicy": "allowlist", "allowFrom": ["wxid_..."] } }`) |
|
|
155
|
-
| `pollIntervalMs` | integer | `1000` | Message polling interval |
|
|
156
|
-
| `authPollIntervalMs` | integer | `30000` | Auth status check interval |
|
|
67
|
+
Set `native.gatewayFacade: {"enabled": true}` to register `/plugins/agent-wechat/native` on the Gateway. The default is disabled. A custom prefix must remain namespaced under `/plugins/...`; changing daemon configuration requires a Gateway reload.
|
|
157
68
|
|
|
158
|
-
|
|
159
|
-
gating) are made by OpenClaw's channel ingress policy, so `accessGroup:<name>` entries from
|
|
160
|
-
the top-level `accessGroups` config work in every allowlist. The pairing store is not
|
|
161
|
-
used: WeChat has no pairing flow.
|
|
69
|
+
The actual Gateway authenticates requests before the proxy runs. Its bearer is never forwarded to the daemon; the plugin uses its private daemon token reference. Routes are restricted to the configured account, with no daemon-wide token/account administration. Binary bodies, byte ranges, status codes and SSE are preserved within explicit size limits. Client disconnect/plugin shutdown closes upstream streaming work without cancelling durable sends.
|
|
162
70
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
### Build from source
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
git clone https://github.com/thisnick/agent-wechat.git
|
|
169
|
-
cd agent-wechat
|
|
170
|
-
pnpm install && pnpm build
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Link for local development
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
openclaw plugins install -l ./packages/openclaw-extension
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
This symlinks the extension so changes are picked up without reinstalling. Rebuild with `pnpm build` after making changes, then restart the gateway.
|
|
180
|
-
|
|
181
|
-
## Architecture
|
|
182
|
-
|
|
183
|
-
```
|
|
184
|
-
OpenClaw Gateway
|
|
185
|
-
└── WeChat Monitor (polling loop)
|
|
186
|
-
│
|
|
187
|
-
│ GET /api/chats (list chats with unreads)
|
|
188
|
-
│ POST /api/chats/{id}/open (open chat, clear unreads)
|
|
189
|
-
│ GET /api/messages/{id} (fetch new messages)
|
|
190
|
-
│ GET /api/messages/{id}/media/{localId} (download media)
|
|
191
|
-
│ POST /api/messages/send (send reply)
|
|
192
|
-
│
|
|
193
|
-
▼
|
|
194
|
-
agent-wechat container (port 6174)
|
|
195
|
-
│
|
|
196
|
-
▼
|
|
197
|
-
WeChat Desktop (in Xvfb)
|
|
198
|
-
```
|
|
71
|
+
`scripts/native-gateway-smoke.mjs` tests the built plugin on an isolated OpenClaw **2026.10.2** Gateway with synthetic loopback data: auth rejection, separate credentials, account boundaries, Range206, SSE and cancellation. This transport test is separate from the local model-boundary test above; neither uses an external model provider or a real WeChat account.
|
|
199
72
|
|
|
200
|
-
|
|
73
|
+
See [native deployment examples](../../deploy/native/README.md) and [native CLI installation](../cli/README.md).
|