Skip to main content

wechat-agent-sdk

English | 中文

WeChat AI Agent bridge framework — connect any AI backend to WeChat with a simple Agent interface, or embed as a transport layer in your platform.

Supports ACP (Agent Client Protocol) to bridge Claude Code, Codex, Kimi, and other ACP-compatible agents directly to WeChat.

This is not an official WeChat project. Built on the iLink Bot API, for learning and research purposes only.

Architecture

The SDK has a two-layer design:

┌─────────────────────────────────────────────────┐
│           Bot Layer (full-stack mode)            │
│  WeChatBot / Builder / Manager / Middleware      │
│  Agent.chat() dispatching                        │
│  For: standalone developers                      │
└──────────────────────┬──────────────────────────┘
                       │ uses internally
┌──────────────────────▼──────────────────────────┐
│         Transport Layer (headless mode)          │
│  WeChatTransport                                 │
│  connect / messages / parse / send / login       │
│  For: platform integration                       │
└──────────────────────┬──────────────────────────┘
                       │ uses internally
┌──────────────────────▼──────────────────────────┐
│              Infrastructure                      │
│  ILinkBotClient (7 API endpoints)                │
│  MediaPipeline (AES + CDN upload/download)       │
│  AccountStorage (JSON / Redis / SQLite)          │
└─────────────────────────────────────────────────┘

Standalone developers use the Bot layer — implement Agent.chat(), call bot.run(), done.

Platform integrators use the Transport layer — consume transport.messages(), handle routing/agents yourself, call transport.send_text() to reply.

Installation

pip install wechat-agent-sdk

Optional dependencies:

pip install 'wechat-agent-sdk[qr]'       # Terminal QR code display
pip install 'wechat-agent-sdk[acp]'       # ACP protocol (Claude Code / Codex / Kimi)
pip install 'wechat-agent-sdk[openai]'    # OpenAI integration
pip install 'wechat-agent-sdk[redis]'     # Redis storage backend
pip install 'wechat-agent-sdk[sqlite]'    # SQLite storage backend
pip install 'wechat-agent-sdk[all]'       # Everything

Requires Python >= 3.11

Quick Start (Bot Layer)

For standalone developers who want a bot running in 5 minutes:

import asyncio
from wechat_agent_sdk import Agent, ChatRequest, ChatResponse, WeChatBot

class EchoAgent(Agent):
    async def chat(self, request: ChatRequest) -> ChatResponse:
        return ChatResponse(text=f"You said: {request.text}")

async def main():
    bot = WeChatBot(agent=EchoAgent())
    await bot.run()

asyncio.run(main())

Using the Builder pattern:

bot = (
    WeChatBot.builder()
    .agent(EchoAgent())
    .account_id("my_bot")
    .storage(RedisStorage("redis://localhost"))
    .middleware(rate_limit_middleware)
    .on_error(my_error_handler)
    .build()
)
await bot.run()

Transport Layer (Platform Integration)

For platforms that have their own agent execution layer, pipeline, and session management. The Transport layer provides only: connect, receive, parse, send.

import asyncio
from wechat_agent_sdk import WeChatTransport, ParsedMessage

async def main():
    transport = WeChatTransport(
        account_id="bot_1",
        storage=my_redis_storage,
    )

    # Web login (for platforms with web UI)
    session = await transport.request_login()
    # ... show session.qr_url in your web UI ...
    result = await transport.check_login(session)

    # Or terminal login
    # await transport.login_terminal()

    # Receive messages
    await transport.connect()
    async for raw_msg in transport.messages():
        parsed = transport.parse(raw_msg)
        if not parsed:
            continue

        # Your platform handles everything from here:
        # permission checks, session management, agent execution, SSE streaming...
        reply = await your_pipeline.handle(parsed)

        # Send reply via transport
        await transport.send_text(parsed.conversation_id, reply, parsed.context_token)

    await transport.disconnect()

asyncio.run(main())

Transport API

Method Description
connect() / disconnect() Manage connection lifecycle
messages() Async iterator — long-poll for messages (auto dedup + cursor)
parse(raw) Parse raw iLink message → ParsedMessage
send_text(chat_id, text) Send text (auto markdown strip + split)
send_text_raw(chat_id, text) Send raw text (no processing)
send_media(chat_id, data, type) Encrypt + upload + send media
download_media(media) Download + decrypt media attachment
send_typing(chat_id, start) Typing indicator
request_login() Get QR URL for web login
check_login(session) Poll login status
login_terminal() Interactive terminal QR login
logout() Clear token, force re-login
activate_token(token) Inject token (after platform re-login)
needs_login Property: True when no valid token

Integration Patterns

Pattern A: Claude Code via ACP

npm install -g @zed-industries/claude-code-acp
pip install 'wechat-agent-sdk[acp,qr]'
from wechat_agent_sdk import WeChatBot
from wechat_agent_sdk.acp.adapter import AcpAgent

agent = AcpAgent(command="claude-agent-acp", permission_mode="bypassPermissions")
bot = WeChatBot(agent=agent)
await bot.run()

Supported ACP agents:

Agent Install Command
Claude Code npm i -g @zed-industries/claude-code-acp claude-agent-acp
Codex npm i -g @openai/codex-acp codex-acp
Kimi CLI npm i -g kimi-cli kimi (args: ["acp"])

Pattern B: OpenAI / Compatible APIs

class OpenAIAgent(Agent):
    async def on_start(self):
        from openai import AsyncOpenAI
        self._client = AsyncOpenAI()

    async def chat(self, request: ChatRequest) -> ChatResponse:
        resp = await self._client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": request.text}],
        )
        return ChatResponse(text=resp.choices[0].message.content)

Pattern C: Multi-Account

from wechat_agent_sdk import WeChatBotManager

manager = WeChatBotManager(storage=my_storage, auto_restart=True)
manager.add_bot("bot_1", agent=AgentA())
manager.add_bot("bot_2", agent=AgentB())

await manager.start_all()
# manager.get_status() → {"bot_1": RUNNING, "bot_2": RUNNING}
await manager.stop_all()

Middleware

Bot layer supports an onion middleware chain (inspired by aiogram / Bot Framework):

async def logging_mw(ctx, next_fn):
    print(f"Received: {ctx.request.text}")
    await next_fn()  # call next middleware / handler
    print(f"Replied: {ctx.response.text if ctx.response else 'None'}")

async def rate_limit(ctx, next_fn):
    if is_rate_limited(ctx.request.conversation_id):
        ctx.response = ChatResponse(text="Please slow down")
        return  # short-circuit, don't call next
    await next_fn()

bot = WeChatBot.builder().agent(my_agent).middleware(logging_mw).middleware(rate_limit).build()

Error handling via middleware:

async def my_error_handler(ctx, error):
    await alert_ops_team(error)
    return ChatResponse(text="Something went wrong, please retry")

bot = WeChatBot.builder().agent(my_agent).on_error(my_error_handler).build()

Concurrent Message Handling

By default, the Bot layer processes up to 10 messages concurrently. When agent.chat() takes a long time (e.g. AcpAgent calling Claude Code), other users' messages are handled in parallel instead of queuing.

# Default: 10 concurrent handlers
bot = WeChatBot(agent=my_agent)

# Custom concurrency limit
bot = WeChatBot(agent=my_agent, max_concurrent=20)

# Via builder
bot = WeChatBot.builder().agent(my_agent).max_concurrent(5).build()

Bounded by asyncio.Semaphore — when the limit is reached, new messages wait until a slot opens. Transport layer does not manage concurrency; platform integrators control their own.

Storage Backends

Backend Install Usage
JSON file (default) built-in JsonFileStorage()
Redis pip install 'wechat-agent-sdk[redis]' from wechat_agent_sdk.account.redis_storage import RedisStorage
SQLite pip install 'wechat-agent-sdk[sqlite]' from wechat_agent_sdk.account.sqlite_storage import SqliteStorage
from wechat_agent_sdk.account.redis_storage import RedisStorage

storage = RedisStorage(url="redis://localhost:6379", prefix="wechat-sdk")
bot = WeChatBot(agent=my_agent, storage=storage)

API Reference

ParsedMessage (Transport layer)

Field Type Description
conversation_id str User wxid (DM) or group ID
text str Text content (voice auto-transcribed)
media list[MediaInfo] All media attachments (supports multi-image)
message_id str Unique message ID
context_token str Must echo back when replying
group_id str | None Group ID (group chats)
sender_id str | None Sender wxid (group chats)
sender_name str | None Sender nickname (group chats)
is_at_bot bool Whether bot was @mentioned
raw dict | None Raw iLink message

ChatRequest (Bot layer)

Same fields as ParsedMessage except media is MediaInfo | None (first attachment only) and no context_token (handled internally).

ChatResponse

Field Type Description
text str | None Reply text (markdown auto-stripped)
media MediaResponseInfo | None Reply media (image/video/file)

MediaInfo

Field Type Description
type str "image" / "audio" / "video" / "file"
cdn_param str CDN encrypted query param (for download)
aes_key str Base64 AES key
file_name str | None Original filename

Download media: data = await transport.download_media(media_info)

Supported Message Types

Inbound (WeChat → Agent)

Type Behavior
Text text contains the message
Image text is "[图片]", media contains CDN reference for download
Voice Transcribed text if available, else "[语音]"
Video text is "[视频]", media contains CDN reference
File text is "[文件: xxx.pdf]", media contains CDN reference
Quote Quoted text prepended: "[引用: original] new message"

Outbound (Agent → WeChat)

Type Usage
Text ChatResponse(text="...")
Long text Auto-split at paragraph boundaries (max 2000 chars)
Markdown Auto-stripped to plain text
Image/Video/File ChatResponse(media=MediaResponseInfo(type="image", url="path_or_url"))

Project Structure

src/wechat_agent_sdk/
├── __init__.py              # Public API exports
├── agent.py                 # Agent abstract base class
├── types.py                 # ChatRequest, ChatResponse, MediaInfo
├── transport.py             # WeChatTransport + ParsedMessage (transport layer)
├── middleware.py             # MiddlewareChain + Context (bot layer)
├── api/
│   ├── client.py            # ILinkBotClient (7 API endpoints)
│   ├── auth.py              # Login flow + LoginSession/LoginResult
│   └── types.py             # iLink API data models
├── messaging/
│   ├── process.py           # Inbound message parsing
│   ├── send.py              # Text splitting + markdown conversion
│   └── monitor.py           # Legacy monitor (kept for backward compat)
├── media/
│   ├── crypto.py            # AES-128-ECB + dual-format key decoding
│   └── cdn.py               # CDN upload / download
├── acp/
│   └── adapter.py           # AcpAgent: ACP subprocess bridge
├── account/
│   ├── manager.py           # WeChatBot + WeChatBotBuilder
│   ├── bot_manager.py       # WeChatBotManager (multi-account)
│   ├── storage.py           # AccountStorage ABC + JsonFileStorage
│   ├── redis_storage.py     # RedisStorage (optional)
│   └── sqlite_storage.py    # SqliteStorage (optional)
└── utils/
    └── markdown.py          # strip_markdown()

Acknowledgements

License

MIT

Metadata

Release files for wechat-agent-sdk 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wechat-agent-sdk 0.2.1
File Size Uploaded Provenance Actions
wechat_agent_sdk-0.2.1.tar.gz 49.2 kB Without provenance Details for wechat_agent_sdk-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for wechat-agent-sdk 0.2.1
File Interpreter ABI Platform Actions
wechat_agent_sdk-0.2.1-py3-none-any.whl Python 3 none any Details for wechat_agent_sdk-0.2.1-py3-none-any.whl

Total release size: 90.5 kB

Release files / wechat_agent_sdk-0.2.1.tar.gz

Download URL wechat_agent_sdk-0.2.1.tar.gz
Size 49.2 kB
Tags Source
SHA-256 checksum
How to use checksums
ee4fc73d61cb39e29b725dfc49f6f99b4f6a5fecfceb4f07c6fb3228a3529320
BLAKE2b-256 checksum
How to use checksums
bb098d5db94609153355ec869134cb13c5614ca92b7e7672f703d43123939b23
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release files / wechat_agent_sdk-0.2.1-py3-none-any.whl

Download URL wechat_agent_sdk-0.2.1-py3-none-any.whl
Size 41.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1dff9ed7c0a519792f33e5dcd5ef5f2b5b03a86770b842651dd7986ddc5b2af1
BLAKE2b-256 checksum
How to use checksums
32ac027b96180354d9f502e07a5641bfda4fb271ef1e38bf555fadca21acc694
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Security for wechat-agent-sdk 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page