@pawastation/wechat-kf 0.2.0 → 0.2.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 +122 -237
- package/README.zh-CN.md +149 -324
- package/dist/src/bot.js +72 -12
- package/dist/src/bot.js.map +1 -1
- package/dist/src/config-schema.d.ts +6 -0
- package/dist/src/config-schema.js +6 -0
- package/dist/src/config-schema.js.map +1 -1
- package/dist/src/types.d.ts +1 -0
- package/openclaw.plugin.json +5 -3
- package/package.json +2 -3
- package/index.ts +0 -42
package/README.md
CHANGED
|
@@ -6,36 +6,65 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://openclaw.dev)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Let WeChat users chat with your OpenClaw AI agent via **WeChat Customer Service**.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
15
|
+
- **No follow required** — users tap a link to start chatting, no need to follow any account first
|
|
16
|
+
- **Rich message types** — send and receive text, images, voice, video, files, link cards, mini-program cards, menus, and more
|
|
17
|
+
- **Markdown styling** — bold, lists, and headings render as Unicode-styled text in WeChat
|
|
18
|
+
- **Free to use** — the WeChat KF API itself is free; no enterprise verification required
|
|
19
|
+
- **Easy setup** — no domain verification, no IP whitelist; a free Cloudflare Tunnel is enough
|
|
20
|
+
|
|
21
|
+
### Inbound message types
|
|
22
|
+
|
|
23
|
+
| Type | Notes |
|
|
24
|
+
| ----------------------- | ----------------------------------------------------------------------------------------- |
|
|
25
|
+
| Text | Plain text, including menu callbacks |
|
|
26
|
+
| Image | Image attachments |
|
|
27
|
+
| Voice | AMR-format voice messages |
|
|
28
|
+
| Video | Video attachments |
|
|
29
|
+
| File | Any file attachment |
|
|
30
|
+
| Link | Shared link cards |
|
|
31
|
+
| Mini-program | Mini-program cards |
|
|
32
|
+
| Location | Geographic location with coordinates |
|
|
33
|
+
| Merged messages | Forwarded message bundles |
|
|
34
|
+
| Channels shop product | Video Channel product cards |
|
|
35
|
+
| Channels shop order | Video Channel order messages |
|
|
36
|
+
| Channels post/live/card | Video Channel post, live, or profile card; only partial fields returned (nickname, title) |
|
|
37
|
+
| User notes | Type detected only; API does not expose note content |
|
|
38
|
+
|
|
39
|
+
### Outbound message types
|
|
40
|
+
|
|
41
|
+
| Type | Notes |
|
|
42
|
+
| ----------------- | ------------------------------ |
|
|
43
|
+
| Text | Plain text |
|
|
44
|
+
| Image | Image attachments |
|
|
45
|
+
| Voice | AMR voice |
|
|
46
|
+
| Video | Video attachments |
|
|
47
|
+
| File | Any file |
|
|
48
|
+
| Link card | Rich link with thumbnail |
|
|
49
|
+
| Mini-program card | Mini-program jump card |
|
|
50
|
+
| Menu | Quick-reply menu buttons |
|
|
51
|
+
| Business card | Employee contact card |
|
|
52
|
+
| Location | Geographic location |
|
|
53
|
+
| Acquisition link | Customer acquisition link card |
|
|
54
|
+
|
|
55
|
+
### WeChat-specific features
|
|
56
|
+
|
|
57
|
+
- **Markdown → Unicode styling** — bold, lists, and headings in agent replies are converted to Unicode-styled characters that render visually in WeChat (e.g., 𝗯𝗼𝗹𝗱 text, bullet symbols)
|
|
58
|
+
- **Message debounce** (`debounceMs`) — when a user sends multiple messages in rapid succession, the plugin waits until no new message arrives within the window, then delivers them all together to the agent as a single turn
|
|
59
|
+
|
|
60
|
+
---
|
|
32
61
|
|
|
33
62
|
## Prerequisites
|
|
34
63
|
|
|
35
|
-
1. A **WeCom account** (企业微信) with
|
|
36
|
-
2.
|
|
37
|
-
|
|
38
|
-
|
|
64
|
+
1. A **WeCom account** (企业微信) — register with the WeCom app (personal accounts work; no real company required)
|
|
65
|
+
2. **OpenClaw** installed and running — see [OpenClaw docs](https://docs.openclaw.ai/)
|
|
66
|
+
|
|
67
|
+
---
|
|
39
68
|
|
|
40
69
|
## Installation
|
|
41
70
|
|
|
@@ -43,254 +72,110 @@
|
|
|
43
72
|
openclaw plugins install @pawastation/wechat-kf
|
|
44
73
|
```
|
|
45
74
|
|
|
46
|
-
|
|
75
|
+
---
|
|
47
76
|
|
|
48
|
-
|
|
77
|
+
## Setup guide
|
|
49
78
|
|
|
50
|
-
|
|
79
|
+
> The WeCom and WeChat KF admin consoles are in Chinese. For detailed step-by-step screenshots, see the [Chinese setup guide](./README.zh-CN.md#快速开始).
|
|
51
80
|
|
|
52
|
-
|
|
53
|
-
| ---------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
54
|
-
| **Admin console** | [WeCom Admin](https://work.weixin.qq.com/wework_admin/frame) | [WeChat KF Admin](https://work.weixin.qq.com/kf/) |
|
|
55
|
-
| **Secret source** | Self-built app secret | WeChat KF dedicated secret |
|
|
56
|
-
| **Callback config location** | WeCom Admin > WeChat KF > API > Callback settings | WeChat KF Admin > Dev Config > Callback settings |
|
|
57
|
-
| **Callback URL requirement** | Must use a verified corporate domain (trusted domain configured in WeCom Admin) | No restriction — any publicly accessible URL works |
|
|
58
|
-
| **Requires self-built app** | Yes — create an app and grant KF API permissions | No — configure directly in the KF admin console |
|
|
59
|
-
| **IP whitelist** | Required (self-built app security requirement) | Not required |
|
|
60
|
-
| **API scope** | Full — can call other WeCom APIs alongside KF | Limited to WeChat KF APIs only |
|
|
61
|
-
| **Best for** | Teams with existing WeCom integrations | Developers who only need AI customer service |
|
|
62
|
-
| **Complexity** | Higher — create app, grant permissions, configure IP whitelist | Lower — enable API and go |
|
|
81
|
+
**Step 1 — Install a tunnel**
|
|
63
82
|
|
|
64
|
-
|
|
83
|
+
WeChat KF requires a public callback URL. Start a Cloudflare Tunnel:
|
|
65
84
|
|
|
66
|
-
|
|
85
|
+
```bash
|
|
86
|
+
cloudflared tunnel --url http://localhost:7860 # replace with your gateway port
|
|
87
|
+
```
|
|
67
88
|
|
|
68
|
-
|
|
89
|
+
Note the `https://xxxx.trycloudflare.com` URL it prints.
|
|
69
90
|
|
|
70
|
-
|
|
71
|
-
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
72
|
-
| **Corp ID** (`corpId`) | WeCom Admin > My Enterprise > Enterprise ID (format: `wwXXXXXXXXXXXXXXXX`) |
|
|
73
|
-
| **App Secret** (`appSecret`) | Method 1: WeCom Admin > App Management > App Details > Secret; Method 2: WeChat KF Admin > Dev Config > Secret |
|
|
74
|
-
| **Token** (`token`) | Generated when configuring callback URL (any random string, up to 32 chars) |
|
|
75
|
-
| **EncodingAESKey** (`encodingAESKey`) | Generated when configuring callback URL (43-char string) |
|
|
91
|
+
**Step 2 — Get your Corp ID**
|
|
76
92
|
|
|
77
|
-
|
|
93
|
+
In the [WeCom Admin console](https://work.weixin.qq.com/wework_admin/frame), go to **My Enterprise** and copy the **Enterprise ID** (format: `wwXXXXXXXXXXXXXXXX`).
|
|
78
94
|
|
|
79
|
-
|
|
95
|
+
**Step 3 — Create a KF account**
|
|
80
96
|
|
|
81
|
-
|
|
82
|
-
- **Method 2** (微信客服后台 API 托管): Enabling the API directly from the KF admin console (5 steps)
|
|
83
|
-
- A detailed comparison table of both methods
|
|
97
|
+
Open [kf.weixin.qq.com](https://kf.weixin.qq.com/) (scan QR with WeCom app), create a customer service account.
|
|
84
98
|
|
|
85
|
-
|
|
99
|
+
**Step 4 — Configure callback in WeChat KF admin**
|
|
86
100
|
|
|
87
|
-
|
|
101
|
+
In [kf.weixin.qq.com](https://kf.weixin.qq.com/) → **Dev Config** → **Get Started**:
|
|
102
|
+
|
|
103
|
+
1. Set callback URL to `https://xxxx.trycloudflare.com/wechat-kf`
|
|
104
|
+
2. Click **Random** to generate Token and EncodingAESKey
|
|
105
|
+
|
|
106
|
+
**Copy the Token and EncodingAESKey — do not click Save yet.** Configure OpenClaw first (next step), then come back to save.
|
|
107
|
+
|
|
108
|
+
**Step 5 — Configure OpenClaw (use a placeholder secret)**
|
|
109
|
+
|
|
110
|
+
Add the channel to OpenClaw config and enable it. Fill in the Token and EncodingAESKey from step 4; use a placeholder for `appSecret` for now. **Save the config.**
|
|
88
111
|
|
|
89
112
|
```yaml
|
|
90
113
|
channels:
|
|
91
114
|
wechat-kf:
|
|
92
115
|
enabled: true
|
|
93
|
-
corpId: "wwXXXXXXXXXXXXXXXX"
|
|
94
|
-
appSecret: "
|
|
95
|
-
token: "
|
|
96
|
-
encodingAESKey: "
|
|
97
|
-
webhookPath: "/wechat-kf" # URL path for webhook (default: /wechat-kf)
|
|
98
|
-
dmPolicy: "open" # Access control: open | allowlist | pairing | disabled
|
|
99
|
-
# allowFrom: # Only used with dmPolicy: allowlist
|
|
100
|
-
# - "external_userid_1"
|
|
101
|
-
# - "external_userid_2"
|
|
116
|
+
corpId: "wwXXXXXXXXXXXXXXXX"
|
|
117
|
+
appSecret: "placeholder" # replace in step 7
|
|
118
|
+
token: "" # from step 4
|
|
119
|
+
encodingAESKey: "" # from step 4
|
|
102
120
|
```
|
|
103
121
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
| Field | Type | Required | Default | Description |
|
|
107
|
-
| ---------------- | -------- | -------- | ------------ | ------------------------------------------------------- |
|
|
108
|
-
| `enabled` | boolean | No | `false` | Enable the channel |
|
|
109
|
-
| `corpId` | string | **Yes** | — | WeCom Corp ID |
|
|
110
|
-
| `appSecret` | string | **Yes** | — | Self-built app secret or WeChat KF secret |
|
|
111
|
-
| `token` | string | **Yes** | — | Webhook callback token |
|
|
112
|
-
| `encodingAESKey` | string | **Yes** | — | 43-char AES key for message encryption |
|
|
113
|
-
| `webhookPath` | string | No | `/wechat-kf` | URL path for webhook callbacks |
|
|
114
|
-
| `dmPolicy` | string | No | `"open"` | `open` / `allowlist` / `pairing` / `disabled` |
|
|
115
|
-
| `allowFrom` | string[] | No | `[]` | Allowed external_userids (when dmPolicy is `allowlist`) |
|
|
116
|
-
|
|
117
|
-
## Verification
|
|
118
|
-
|
|
119
|
-
1. Start the gateway:
|
|
120
|
-
```bash
|
|
121
|
-
openclaw gateway start
|
|
122
|
-
```
|
|
123
|
-
2. Expose the gateway to the public internet (if not on a public server). Option A — Tailscale Funnel (built-in):
|
|
124
|
-
```bash
|
|
125
|
-
openclaw gateway --tailscale funnel --auth password
|
|
126
|
-
```
|
|
127
|
-
Option B — ngrok:
|
|
128
|
-
```bash
|
|
129
|
-
ngrok http <gateway-port>
|
|
130
|
-
```
|
|
131
|
-
3. Copy the HTTPS URL (e.g. `https://your-machine.tail1234.ts.net` or `https://xxxx.ngrok-free.app`) and set the callback URL in WeCom:
|
|
132
|
-
```
|
|
133
|
-
https://<your-public-host>/wechat-kf
|
|
134
|
-
```
|
|
135
|
-
4. WeCom sends a GET verification request — the plugin decrypts the `echostr` and responds automatically
|
|
136
|
-
5. Send a test message from WeChat (via the KF link) and confirm the agent responds
|
|
137
|
-
|
|
138
|
-
## Usage
|
|
139
|
-
|
|
140
|
-
Once configured and running, the plugin works automatically:
|
|
141
|
-
|
|
142
|
-
1. **Users** tap your Customer Service link in WeChat to start a conversation
|
|
143
|
-
2. **Inbound messages** arrive via webhook — the plugin decrypts, syncs messages via `sync_msg`, downloads any media, and dispatches to your OpenClaw agent
|
|
144
|
-
3. **The agent** processes the message and generates a reply
|
|
145
|
-
4. **Outbound replies** are sent back via the WeCom `send_msg` API, with markdown automatically converted to Unicode-styled plain text
|
|
146
|
-
|
|
147
|
-
### Sending messages from the agent
|
|
148
|
-
|
|
149
|
-
The agent can use the `message` tool to send messages:
|
|
150
|
-
|
|
151
|
-
- **Reply to current conversation** — omit `target`; the reply goes to whoever messaged
|
|
152
|
-
- **Send to a specific user** — set `target` to the user's `external_userid`
|
|
153
|
-
- **Send media** — use `filePath` or `media` to attach images, voice, video, or files
|
|
154
|
-
|
|
155
|
-
### Supported inbound message types
|
|
156
|
-
|
|
157
|
-
| WeChat Type | How it's handled |
|
|
158
|
-
| ------------------------ | --------------------------------------------------------------------- |
|
|
159
|
-
| Text | Passed as-is to the agent |
|
|
160
|
-
| Image | Downloaded, saved as media attachment, placeholder text sent to agent |
|
|
161
|
-
| Voice | Downloaded as AMR, saved as media attachment |
|
|
162
|
-
| Video | Downloaded as MP4, saved as media attachment |
|
|
163
|
-
| File | Downloaded, saved as media attachment |
|
|
164
|
-
| Location | Converted to text: `[Location: name address]` |
|
|
165
|
-
| Link | Converted to text: `[Link: title url]` (with desc, pic_url) |
|
|
166
|
-
| Mini Program | Converted to text with title, appid, and pagepath |
|
|
167
|
-
| Channels (Video Account) | Converted to text with type, nickname, title |
|
|
168
|
-
| Channels Shop Product | Converted to text with product info |
|
|
169
|
-
| Channels Shop Order | Converted to text with order info |
|
|
170
|
-
| Note | Converted to text with note content |
|
|
171
|
-
| Business Card | Converted to text with userid |
|
|
172
|
-
| Forwarded Messages | Parsed and expanded into readable text |
|
|
173
|
-
|
|
174
|
-
### Supported outbound message types
|
|
175
|
-
|
|
176
|
-
Text, image, voice, video, file, link, location, mini-program, menu, business card, channel article, and raw JSON messages (`[[wechat_raw:...]]`). Rich message types are sent via `[[wechat_*:...]]` text directives. Media from any source (local files, HTTP URLs, file:// URIs) is loaded via the framework's loadWebMedia and uploaded to WeChat's temporary media storage before sending.
|
|
177
|
-
|
|
178
|
-
## Architecture
|
|
122
|
+
Once saved, OpenClaw starts listening on the callback URL, so WeChat's verification request in the next step can succeed.
|
|
179
123
|
|
|
180
|
-
|
|
181
|
-
WeChat User
|
|
182
|
-
|
|
|
183
|
-
v
|
|
184
|
-
WeCom Server (Tencent)
|
|
185
|
-
|
|
|
186
|
-
|--- POST callback ---> webhook.ts ---> verify signature + size/method guards
|
|
187
|
-
| (encrypted XML) | decrypt AES-256-CBC
|
|
188
|
-
| | extract OpenKfId + Token
|
|
189
|
-
| v
|
|
190
|
-
| bot.ts ---> DM policy check
|
|
191
|
-
| | per-kfId mutex + msgid dedup
|
|
192
|
-
| | sync_msg API (pull messages)
|
|
193
|
-
| | cursor-based incremental sync
|
|
194
|
-
| | handle events (enter_session, etc.)
|
|
195
|
-
| | download media attachments
|
|
196
|
-
| v
|
|
197
|
-
| OpenClaw Agent (dispatch via runtime)
|
|
198
|
-
| |
|
|
199
|
-
| +-----------+-----------+
|
|
200
|
-
| v v
|
|
201
|
-
| outbound.ts reply-dispatcher.ts
|
|
202
|
-
| (framework-driven) (plugin-internal streaming)
|
|
203
|
-
| chunker declaration markdown -> unicode
|
|
204
|
-
| sendText / sendMedia text chunking + delay
|
|
205
|
-
| | |
|
|
206
|
-
| +-----------+-----------+
|
|
207
|
-
| v
|
|
208
|
-
| send-utils.ts
|
|
209
|
-
| formatText, mediaKindToWechatType
|
|
210
|
-
| detectMediaType, uploadAndSendMedia
|
|
211
|
-
| resolveThumbMediaId
|
|
212
|
-
| v
|
|
213
|
-
+--- send_msg API <--- api.ts
|
|
214
|
-
(JSON)
|
|
215
|
-
```
|
|
124
|
+
**Step 6 — Back to WeChat KF admin: verify and copy Secret**
|
|
216
125
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
| `constants.ts` | Shared constants (WECHAT_TEXT_CHUNK_LIMIT, timeouts, error codes) |
|
|
233
|
-
| `fs-utils.ts` | Atomic file operations (temp file + rename) |
|
|
234
|
-
| `unicode-format.ts` | Markdown to Unicode Mathematical styled text |
|
|
235
|
-
| `channel.ts` | ChannelPlugin interface with security adapter (resolveDmPolicy, collectWarnings) |
|
|
236
|
-
| `config-schema.ts` | JSON Schema for wechat-kf channel config validation |
|
|
237
|
-
| `runtime.ts` | OpenClaw runtime reference holder |
|
|
238
|
-
|
|
239
|
-
### State persistence
|
|
240
|
-
|
|
241
|
-
- **Sync cursors** — saved per KF account in `~/.openclaw/state/wechat-kf/wechat-kf-cursor-{kfid}.txt` (atomic writes)
|
|
242
|
-
- **Discovered KF IDs** — saved in `~/.openclaw/state/wechat-kf/wechat-kf-kfids.json` (atomic writes)
|
|
243
|
-
- **Access tokens** — in-memory only with hashed cache key (re-fetched on restart)
|
|
244
|
-
|
|
245
|
-
## Limitations / Known Issues
|
|
246
|
-
|
|
247
|
-
- **Open access by design** — WeChat Customer Service is inherently a public-facing service within the WeChat ecosystem. Anyone who obtains the KF contact link (URL or QR code) can send messages to your KF account — this cannot be prevented at the WeChat platform level. The plugin's `dmPolicy: "allowlist"` mode can restrict which users the agent actually responds to (non-allowlisted messages are silently dropped), but it cannot prevent unknown users from reaching the KF entry point itself. Please be aware of this public-facing nature when deploying in production.
|
|
248
|
-
- **48-hour reply window** — WeChat only allows replies within 48 hours of the user's last message. The plugin detects this (errcode 95026) and logs a clear warning.
|
|
249
|
-
- **5 messages per window** — you can send at most 5 replies before the user sends another message. The plugin detects this limit and logs accordingly.
|
|
250
|
-
- **Voice format** — inbound voice messages are AMR format; transcription depends on the OpenClaw agent's media processing capabilities.
|
|
251
|
-
- **Temporary media only** — uploaded media uses WeChat's temporary media API (3-day expiry). Permanent media upload is not implemented.
|
|
252
|
-
- **Single webhook endpoint** — all KF accounts share the same webhook path. This is by design (WeCom sends all callbacks to one URL per enterprise).
|
|
253
|
-
- **No group chat** — WeChat KF is direct messaging only. The plugin only supports `direct` chat type.
|
|
254
|
-
- **IP whitelist drift** — if your server's public IP changes, API calls will fail silently. Monitor your IP or use a static IP.
|
|
255
|
-
|
|
256
|
-
## Development
|
|
126
|
+
Back in [kf.weixin.qq.com](https://kf.weixin.qq.com/) → **Dev Config**, click **Save** — WeChat sends a verification request; OpenClaw responds automatically and the config takes effect.
|
|
127
|
+
|
|
128
|
+
On the same page, copy the **App Secret**.
|
|
129
|
+
|
|
130
|
+
**Step 7 — Replace placeholder with real Secret**
|
|
131
|
+
|
|
132
|
+
Replace the placeholder `appSecret` in your OpenClaw config with the value copied in step 6. Save the config.
|
|
133
|
+
|
|
134
|
+
**Step 8 — Get the contact link and test**
|
|
135
|
+
|
|
136
|
+
In the WeChat KF admin, copy the **contact link** for your KF account and open it in WeChat to start chatting with your agent.
|
|
137
|
+
|
|
138
|
+
**Step 9 — (Recommended) Enable pairing mode**
|
|
139
|
+
|
|
140
|
+
To restrict access, set `dmPolicy: "pairing"`. New users receive a pairing code; approve with:
|
|
257
141
|
|
|
258
142
|
```bash
|
|
259
|
-
|
|
260
|
-
|
|
143
|
+
openclaw pairing approve wechat-kf <code>
|
|
144
|
+
```
|
|
261
145
|
|
|
262
|
-
|
|
263
|
-
pnpm run build
|
|
146
|
+
---
|
|
264
147
|
|
|
265
|
-
|
|
266
|
-
pnpm run typecheck
|
|
148
|
+
## Configuration reference
|
|
267
149
|
|
|
268
|
-
|
|
269
|
-
|
|
150
|
+
| Field | Type | Required | Default | Description |
|
|
151
|
+
| ---------------- | -------- | -------- | ------------ | -------------------------------------------------------------------------------------------------------------------------- |
|
|
152
|
+
| `enabled` | boolean | No | `false` | Enable the channel |
|
|
153
|
+
| `corpId` | string | **Yes** | — | WeCom Corp ID |
|
|
154
|
+
| `appSecret` | string | **Yes** | — | WeChat KF secret (from WeChat KF Admin > Dev Config) |
|
|
155
|
+
| `token` | string | **Yes** | — | Webhook callback token |
|
|
156
|
+
| `encodingAESKey` | string | **Yes** | — | 43-char AES key for message encryption |
|
|
157
|
+
| `webhookPath` | string | No | `/wechat-kf` | URL path for webhook callbacks |
|
|
158
|
+
| `dmPolicy` | string | No | `"open"` | `open` / `allowlist` / `pairing` / `disabled` |
|
|
159
|
+
| `allowFrom` | string[] | No | `[]` | Allowed external_userids (when `dmPolicy` is `allowlist`) |
|
|
160
|
+
| `debounceMs` | number | No | `2000` | Debounce window in ms (0–10000): waits until no new message in window, then dispatches all to agent; set to `0` to disable |
|
|
270
161
|
|
|
271
|
-
|
|
272
|
-
pnpm run test:watch
|
|
162
|
+
---
|
|
273
163
|
|
|
274
|
-
|
|
275
|
-
pnpm run lint
|
|
164
|
+
## Limitations
|
|
276
165
|
|
|
277
|
-
|
|
278
|
-
|
|
166
|
+
- **Public by design** — anyone with the contact link can send messages; this cannot be prevented at the platform level. Use `dmPolicy: "pairing"` or `"allowlist"` to control who the agent responds to.
|
|
167
|
+
- **48-hour reply window** — WeChat only allows replies within 48 hours of the user's last message.
|
|
168
|
+
- **5 messages per window** — at most 5 replies before the user sends another message.
|
|
169
|
+
- **Voice format** — inbound voice is AMR; transcription depends on your agent's media capabilities.
|
|
170
|
+
- **Tunnel URL changes** — free Cloudflare Tunnel URLs change on restart. Use a custom domain pointed to your server, a paid tunnel (e.g. Cloudflare Zero Trust), or a static IP for production.
|
|
279
171
|
|
|
280
|
-
|
|
281
|
-
pnpm run format
|
|
172
|
+
---
|
|
282
173
|
|
|
283
|
-
|
|
284
|
-
pnpm run check
|
|
285
|
-
```
|
|
174
|
+
## Developer docs
|
|
286
175
|
|
|
287
|
-
|
|
176
|
+
For architecture, module descriptions, development commands, and contributing workflow, see [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
288
177
|
|
|
289
|
-
|
|
290
|
-
2. Create a feature branch (`git checkout -b feature/my-feature`)
|
|
291
|
-
3. Make your changes and add tests
|
|
292
|
-
4. Run `pnpm run check && pnpm run typecheck && pnpm test` to verify
|
|
293
|
-
5. Submit a pull request
|
|
178
|
+
---
|
|
294
179
|
|
|
295
180
|
## License
|
|
296
181
|
|