@ericzhaozzz/wechat-channel
@ericzhaozzz/wechat-channel — iLink Bot API integration for Pi Agent
Package details
Install @ericzhaozzz/wechat-channel from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@ericzhaozzz/wechat-channel- Package
@ericzhaozzz/wechat-channel- Version
0.3.0- Published
- Aug 31, 2026
- Downloads
- 431/mo · 26/wk
- Author
- ericzhaozzz
- License
- MIT
- Types
- extension
- Size
- 562.1 KB
- Dependencies
- 1 dependency · 2 peers
Pi manifest JSON
{
"extensions": [
"./dist/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@ericzhaozzz/wechat-channel
English | 中文
A pi agent extension that turns your personal WeChat into a remote control for your AI assistant — chat with pi from your phone and get answers, progress and files back in WeChat, via Tencent's iLink Bot API.
Features
- Chat from WeChat, get one coherent answer — messages are forwarded to pi's agent
and replies keep their Markdown. A burst of short messages is merged into a single
numbered turn (
[1],[2], …), and long replies arrive chunked and in order. - Watch the work happen — the typing indicator stays on for the whole turn and
progress lines (
⏳ 正在执行:npm test) show what the agent is doing; queueing, offline replay and undelivered answers are all called out. - Rich media, both ways — images, files, voice and video are auto-downloaded, and received images enter the model's context as image content. The agent can push screenshots, charts and generated files before the answer is finished.
- Control it from your phone —
#status,#queue,#clear,#canceland#helpwork straight from WeChat. - The agent asks you, not the empty terminal — a tool that can only put its question
to a terminal dialog (
ask_user_question) would block the whole turn on a screen nobody is watching. On a WeChat turn those tools are blocked and the agent is told to ask as ordinary numbered text, so the question reaches your phone and "2" is a complete answer. Configurable throughterminalOnlyTools. - One person, one session — exactly one WeChat user is bound as owner and everyone else is dropped silently; the channel belongs to a single pi session.
- Keeps working through trouble — auto-reconnect and re-login, offline traffic is replayed, messages queue instead of dropping, and state survives restarts and crashes.
Installation
# From npm (preferred) — ships the compiled dist/, nothing else needed
pi install npm:@ericzhaozzz/wechat-channel
pi
# Or build from source and copy into pi's extension folder — the compiled
# dist/ is what pi loads (`pi.extensions` points at `./dist/index.js`)
npm install && npm run build # inside the wechat-channel checkout
cd .. && cp -r wechat-channel ~/.pi/agent/extensions/
cd ~/.pi/agent/extensions/wechat-channel
npm install --omit=dev # just the SDK — no tsx at runtime
# Restart pi (or run /reload)
pi
Quick start
- Start pi and run
/wechat login - Scan the QR code with WeChat on your phone and confirm the login
- Send the bot a message from your own WeChat — the first sender is bound as owner
- Your messages are forwarded to pi; replies come back to you automatically
Usage
Commands from WeChat
Away from the terminal, the owner can send these straight to the bot. The prefix is
channelCommandPrefix (default #; an empty string disables them):
| Command | Effect |
|---|---|
#cancel / #停 |
Abort the turn being answered |
#status / #状态 |
Connection, busy or idle, queue depth, context usage |
#queue / #队列 |
How many messages are waiting |
#clear / #清空 |
Drop the queue (the running turn is untouched) |
#help / #帮助 |
List the above |
Only an exact command name counts — a typo like #cancle is forwarded to the agent
like any other message.
Terminal commands
/wechat login, /wechat status, /wechat config, /wechat history, /wechat log --tail, /wechat owner, /wechat send / send-media, /wechat start / stop,
/wechat qr, /wechat cancel, /wechat clean and /wechat prefix cover login, status,
ownership, sending and media (subcommands autocomplete — type /wechat st and press Tab).
pi's footer carries one line of channel state (wechat: ✓ busy q2); disconnects, dropped
answers and the like surface as pi notifications.
Configuration
Everything tunable lives in ~/.pi/wechat/config.json and is read once at load, so
changes apply after /reload. Without the file, the extension behaves exactly as it
ships:
{
"ownerUserId": "wxid_xxx@im.wechat",
"aiPrefix": "",
"autoLogin": true,
"preserveMarkdown": true,
"mergeDebounceMs": 1500,
"maxMergeMessages": 10,
"rateLimitMax": 20,
"rateLimitWindowMs": 60000,
"agentTimeoutMs": 3600000,
"maxDeliveryAttempts": 3,
"deliveryParkTimeoutMs": 600000,
"progressUpdates": true,
"progressIntervalMs": 45000,
"notifyFailures": true,
"channelCommandPrefix": "#",
"inlineImages": true,
"maxInlineImageBytes": 5242880,
"terminalOnlyTools": ["ask_user_question"],
"steerWhileBusy": false
}
The commonly tuned ones: channelCommandPrefix (WeChat command prefix), ownerUserId
(pin the owner up front), mergeDebounceMs / maxMergeMessages (short-message merging),
steerWhileBusy (a message arriving mid-turn joins that turn instead of queueing),
inlineImages, progressUpdates and notifyFailures. terminalOnlyTools names the tools
that may not run on a WeChat turn because they can only ask through a terminal dialog —
empty it if you do sit at the terminal, and such a question is relayed to WeChat as a notice
telling you to answer it there. Unreadable values or unknown keys keep their defaults and
are listed by /wechat config.
Security & ownership
Anyone who could reach the bot could otherwise read your files and run commands through
pi, so messages from anyone but the owner are dropped silently. The owner is bound on
first use and persisted to ~/.pi/wechat/owner.json, or pinned up front via
ownerUserId; inspect or change it with /wechat owner.
One iLink account supports one poller, so the channel belongs to a single pi session. A
session that does not own it starts no worker and takes over automatically within ~30 s of
the owner closing; /wechat start --takeover seizes it immediately. A killed pi releases
the channel when its lease expires (~90 s).
Compared to Hermes Agent
| Feature | Hermes Agent | Pi WeChat Extension |
|---|---|---|
| Long-polling | ✅ asyncio Gateway | ✅ Child process |
| QR login | ✅ Built-in | ✅ Built-in |
| Markdown preservation | ✅ | ✅ |
| Sender authorization | ✅ Per-user policy | ✅ Single owner (allowlist of one) |
| Voice transcript / quote reply context | ✅ | ✅ Passed through to the agent |
| Media receive (auto-download) | ✅ Full | ✅ image/file/video/voice (first attachment only) |
| Media send | ✅ Full | ✅ via /wechat send-media (path/url/base64) |
| Multi-user sessions | ✅ Per-user isolation | ⚠️ Single session bridge |
| 24/7 daemon | ✅ systemd/launchd | ⚠️ Requires pi running |
| Typing indicators | ✅ | ✅ |
| Message deduplication | ✅ | ✅ |
| Context token persistence | ✅ | ✅ |
| Smart chunking | ✅ | ✅ |
| SSRF protection | ✅ | ❌ Future |
| Delivery ledger | ✅ | ✅ Bounded retry, persisted |