WeChatBot SDK

repository·main·Indexed 20 days ago

https://github.com/corespeed-io/wechatbot

A modular, production-grade, multi-language SDK for integrating AI Agents and OpenClaw with WeChat iLink. It provides reliable message polling, rich media support, and multi-tenant capabilities with official implementations for Go (wechatbot-go), Node.js (@wechatbot/wechatbot), and Python (wechatbot-sdk), as well as a Pi extension (@wechatbot/pi-agent) for chatting with Pi via WeChat.

Tokens
29.3K
Snippets
118
Records
154
Agent score
68%

What's inside wechatbot

  1. Implement Multi-Tenant / Multi-Account Isolation

    main

    Every WeChatBot instance is fully isolated (own HTTP client, events, and message poller). To run multiple accounts side-by-side without global state conflicts, ensure each instance has its own storage namespace or storageDir.

    When using the Node.js SDK, you can pass a custom storage implementation and use login callbacks to handle QR codes (e.g., pushing them to a specific user's web UI).

    Critical Requirements for Multi-Tenancy:

    1. Storage Isolation: Each account must have its own storageDir or storage namespace to prevent credential overwriting.
    2. Instance Uniqueness: Only one live instance (poller) should run per account to avoid cursor overwrites. Use advisory locks in multi-machine deployments.
    3. Session Persistence: Credentials are saved to disk/storage, so login() will automatically restore sessions after a restart.
    // One instance per tenant, credentials isolated per tenant
    const bot = new WeChatBot({
      storage: new PostgresStorage(pool, tenantId),  // or { storageDir: `/data/${tenantId}` }
    })
    
    await bot.login({
      callbacks: {
        onQrUrl: (url) => pushQrToWebUI(tenantId, url),
        onScanned: () => notify(tenantId, 'Scanned — waiting for confirmation'),
        onExpired: () => refreshQr(tenantId),
      },
    })
    await bot.start()
  2. Understand the Long-Poll Loop and error handling

    main

    The bot maintains a connection to receive updates via a long-polling mechanism:

    1. Polling: The SDK performs a POST /getupdates with a cursor. The server holds this request for up to 35 seconds.
    2. Processing: Messages are parsed, context_tokens are cached, and handlers are dispatched.
    3. Error Handling:
      • Error -14: This indicates a session issue. The SDK clears the state and triggers a re-login.
      • Network Errors: The SDK implements exponential backoff (starting at 1s, capping at 10s) to recover from connectivity issues.
  3. Manage message context with context_token

    main

    To ensure replies are correctly associated with the original conversation, every reply must include the context_token from the incoming message.

    Across all SDKs, the following lifecycle is managed:

    1. Extraction: The SDK automatically extracts the token from incoming messages.
    2. Caching: Tokens are cached in memory per userId.
    3. Injection: The SDK automatically injects the token into outgoing messages when using the reply() method.
    4. Persistence: The Node.js SDK specifically persists these tokens to storage to allow the bot to survive restarts.
  4. Session Recovery and Concurrency in wechatbot-go

    main

    The SDK is designed for production use with the following characteristics:

    • Concurrency: The bot is safe for concurrent use. contextTokens uses sync.Map, credentials are protected by sync.Mutex, and multiple handlers run sequentially per message.
    • Session Recovery: If a -14 (session expired) error is received, the bot automatically clears cached state, deletes stored credentials, initiates a new QR login, and resumes polling.
  5. How the WeChatBot layered architecture works

    main

    The WeChatBot SDKs (Node.js, Python, Go, and Rust) follow a consistent layered architecture. This design separates high-level application logic from low-level protocol handling:

    1. Application Layer: Your custom bot code.
    2. Middleware (Node.js only): An Express-style pipeline for processing messages.
    3. Bot Client: The orchestrator responsible for login, running the bot, and replying.
    4. Core Services: Includes the Poller (fetching updates), Sender (sending messages), Typing (status updates), and Media (handling files).
    5. Context Store: Manages the context_token lifecycle.
    6. Protocol/API: Handles raw HTTP calls to the iLink service.
    7. Transport/HTTP: An HTTP client with built-in retry logic.
    8. Storage: Manages credentials and state persistence.
  6. Node.js Exclusive Features

    main

    The Node.js SDK includes additional developer-experience features:

    • Middleware Pipeline: Composable middleware similar to Express/Koa.
    • Pluggable Storage: Support for File, Memory, or custom implementations like Redis or SQLite.
    • Typed Events: Full IntelliSense support for lifecycle monitoring.
    • Structured Logging: Graded, context-aware, and pluggable transport logging.
    • Message Builder: A chainable API for constructing complex messages: .text().image().file().build().
  7. How text chunking works for long messages

    main

    To comply with platform limits, all SDKs automatically split text that exceeds 2000 characters. The splitting logic follows this priority:

    1. Paragraph break (\n\n)
    2. Line break (\n)
    3. Space
    4. Hard cut (if no other delimiters are found)

    Each resulting chunk is assigned a unique client_id, but all chunks share the same context_token to maintain conversation continuity.

  8. How @wechatbot/pi-agent works

    main

    The extension acts as a bridge between the WeChat iLink API and the Pi coding agent.

    The Workflow:

    1. Connection: Running /wechat creates a WeChatBot instance (via the @wechatbot/wechatbot SDK). The SDK retrieves a QR URL from the iLink API, which the extension renders in the terminal using qrcode-terminal.
    2. Message Inbound: Once logged in, the SDK starts a long-poll. Incoming WeChat messages trigger pi.sendUserMessage(text), which passes the message to Pi as a prompt.
    3. Message Outbound: When Pi finishes processing (the agent_end event), the extension calls bot.reply(text) to send the response back to WeChat.
    4. User Experience: The extension uses bot.sendTyping() to show "对方正在输入中..." (User is typing...) in WeChat while Pi is generating a response.

    Note for Developers: The @wechatbot/wechatbot SDK does not render QR codes. Developers implementing extensions must handle the onQrUrl callback and use a library like qrcode-terminal to display the code.

  9. Understand the QR Login Flow

    main

    All SDKs use a standardized QR code authentication flow:

    1. Request QR: The SDK calls GET /get_bot_qrcode to retrieve a QR URL.
    2. Display: The developer displays this QR to the user.
    3. Polling: The SDK enters a polling loop (checking GET /get_qrcode_status every 2 seconds).
    4. Confirmation: Once the user scans and confirms, the SDK extracts credentials and persists them to ~/.wechatbot/.
    5. Expiration: If the QR expires, the SDK requests a new one.
  10. Core Features of WeChatBot

    main

    All SDKs share the following core capabilities:

    • QR Code Login: Credentials are persisted in ~/.wechatbot/.
    • Long Polling Messages: Reliable message reception with automatic cursor management.
    • Rich Media Support: Upload and download support for images, files, voice, and video.
    • context_token: Automatic lifecycle management and persistence across restarts.
    • Typing Status: Detects when the other party is typing (includes ticket caching).
    • CDN Encryption: AES-128-ECB encryption supporting dual-key formats.
    • Session Recovery: Automatic re-login when a session expires (error code -14).
    • Smart Chunking: Automatically splits text at natural boundaries (paragraphs → lines → spaces).
  11. Quickstart: Python SDK

    main

    In Python, use the WeChatBot class. You can use the @bot.on_message decorator to handle incoming messages and bot.reply() to respond.

    from wechatbot import WeChatBot
    
    bot = WeChatBot()
    
    @bot.on_message
    async def handle(msg):
        await bot.reply(msg, f"Echo: {msg.text}")
    
    bot.run()  # 扫码登录 + 开始监听
  12. Quickstart: Go SDK

    main

    In Go, initialize a bot with wechatbot.New(). Use Login for authentication and OnMessage to register a callback function for handling *wechatbot.IncomingMessage.

    bot := wechatbot.New()
    bot.Login(ctx, false)
    bot.OnMessage(func(msg *wechatbot.IncomingMessage) {
        bot.Reply(ctx, msg, fmt.Sprintf("Echo: %s", msg.Text))
    })
    bot.Run(ctx)