openclaw-home-pc/openclaw/extensions/openclaw-weixin/README.zh_CN.md
2026-03-24 04:00:48 +08:00

272 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 微信
[English](./README.md)
OpenClaw 的微信渠道插件,支持通过扫码完成登录授权。
## 前提条件
已安装 [OpenClaw](https://docs.openclaw.ai/install)(需要 `openclaw` CLI 可用)。
## 一键安装
```bash
npx -y @tencent-weixin/openclaw-weixin-cli install
```
## 手动安装
如果一键安装不适用,可以按以下步骤手动操作:
### 1. 安装插件
```bash
openclaw plugins install "@tencent-weixin/openclaw-weixin"
```
### 2. 启用插件
```bash
openclaw config set plugins.entries.openclaw-weixin.enabled true
```
### 3. 扫码登录
```bash
openclaw channels login --channel openclaw-weixin
```
终端会显示一个二维码,用手机扫码并在手机上确认授权。确认后,登录凭证会自动保存到本地,无需额外操作。
### 4. 重启 gateway
```bash
openclaw gateway restart
```
## 添加更多微信账号
```bash
openclaw channels login --channel openclaw-weixin
```
每次扫码登录都会创建一个新的账号条目,支持多个微信号同时在线。
## 多账号上下文隔离
默认情况下,所有渠道的 AI 会话共享同一个上下文。如果希望每个微信账号的对话上下文相互隔离:
```bash
openclaw config set agents.mode per-channel-per-peer
```
这样每个「微信账号 + 发消息用户」组合都会拥有独立的 AI 记忆,账号之间不会串台。
## 后端 API 协议
本插件通过 HTTP JSON API 与后端网关通信。二次开发者若需对接自有后端,需实现以下接口。
所有接口均为 `POST`,请求和响应均为 JSON。通用请求头
| Header | 说明 |
|--------|------|
| `Content-Type` | `application/json` |
| `AuthorizationType` | 固定值 `ilink_bot_token` |
| `Authorization` | `Bearer <token>`(登录后获取) |
| `X-WECHAT-UIN` | 随机 uint32 的 base64 编码 |
### 接口列表
| 接口 | 路径 | 说明 |
|------|------|------|
| getUpdates | `getupdates` | 长轮询获取新消息 |
| sendMessage | `sendmessage` | 发送消息(文本/图片/视频/文件) |
| getUploadUrl | `getuploadurl` | 获取 CDN 上传预签名 URL |
| getConfig | `getconfig` | 获取账号配置typing ticket 等) |
| sendTyping | `sendtyping` | 发送/取消输入状态指示 |
### getUpdates
长轮询接口。服务端在有新消息或超时后返回。
**请求体:**
```json
{
"get_updates_buf": ""
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `get_updates_buf` | `string` | 上次响应返回的同步游标,首次请求传空字符串 |
**响应体:**
```json
{
"ret": 0,
"msgs": [...],
"get_updates_buf": "<新游标>",
"longpolling_timeout_ms": 35000
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `ret` | `number` | 返回码,`0` = 成功 |
| `errcode` | `number?` | 错误码(如 `-14` = 会话超时) |
| `errmsg` | `string?` | 错误描述 |
| `msgs` | `WeixinMessage[]` | 消息列表(结构见下方) |
| `get_updates_buf` | `string` | 新的同步游标,下次请求时回传 |
| `longpolling_timeout_ms` | `number?` | 服务端建议的下次长轮询超时ms |
### sendMessage
发送一条消息给用户。
**请求体:**
```json
{
"msg": {
"to_user_id": "<目标用户 ID>",
"context_token": "<会话上下文令牌>",
"item_list": [
{
"type": 1,
"text_item": { "text": "你好" }
}
]
}
}
```
### getUploadUrl
获取 CDN 上传预签名参数。上传文件前需先调用此接口获取 `upload_param``thumb_upload_param`
**请求体:**
```json
{
"filekey": "<文件标识>",
"media_type": 1,
"to_user_id": "<目标用户 ID>",
"rawsize": 12345,
"rawfilemd5": "<明文 MD5>",
"filesize": 12352,
"thumb_rawsize": 1024,
"thumb_rawfilemd5": "<缩略图明文 MD5>",
"thumb_filesize": 1040
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `media_type` | `number` | `1` = IMAGE, `2` = VIDEO, `3` = FILE |
| `rawsize` | `number` | 原文件明文大小 |
| `rawfilemd5` | `string` | 原文件明文 MD5 |
| `filesize` | `number` | AES-128-ECB 加密后的密文大小 |
| `thumb_rawsize` | `number?` | 缩略图明文大小IMAGE/VIDEO 时必填) |
| `thumb_rawfilemd5` | `string?` | 缩略图明文 MD5IMAGE/VIDEO 时必填) |
| `thumb_filesize` | `number?` | 缩略图密文大小IMAGE/VIDEO 时必填) |
**响应体:**
```json
{
"upload_param": "<原图上传加密参数>",
"thumb_upload_param": "<缩略图上传加密参数>"
}
```
### getConfig
获取账号配置,包括 typing ticket。
**请求体:**
```json
{
"ilink_user_id": "<用户 ID>",
"context_token": "<可选,会话上下文令牌>"
}
```
**响应体:**
```json
{
"ret": 0,
"typing_ticket": "<base64 编码的 typing ticket>"
}
```
### sendTyping
发送或取消输入状态指示。
**请求体:**
```json
{
"ilink_user_id": "<用户 ID>",
"typing_ticket": "<从 getConfig 获取>",
"status": 1
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `status` | `number` | `1` = 正在输入,`2` = 取消输入 |
### 消息结构
#### WeixinMessage
| 字段 | 类型 | 说明 |
|------|------|------|
| `seq` | `number?` | 消息序列号 |
| `message_id` | `number?` | 消息唯一 ID |
| `from_user_id` | `string?` | 发送者 ID |
| `to_user_id` | `string?` | 接收者 ID |
| `create_time_ms` | `number?` | 创建时间戳ms |
| `session_id` | `string?` | 会话 ID |
| `message_type` | `number?` | `1` = USER, `2` = BOT |
| `message_state` | `number?` | `0` = NEW, `1` = GENERATING, `2` = FINISH |
| `item_list` | `MessageItem[]?` | 消息内容列表 |
| `context_token` | `string?` | 会话上下文令牌,回复时需回传 |
#### MessageItem
| 字段 | 类型 | 说明 |
|------|------|------|
| `type` | `number` | `1` TEXT, `2` IMAGE, `3` VOICE, `4` FILE, `5` VIDEO |
| `text_item` | `{ text: string }?` | 文本内容 |
| `image_item` | `ImageItem?` | 图片(含 CDN 引用和 AES 密钥) |
| `voice_item` | `VoiceItem?` | 语音SILK 编码) |
| `file_item` | `FileItem?` | 文件附件 |
| `video_item` | `VideoItem?` | 视频 |
| `ref_msg` | `RefMessage?` | 引用消息 |
#### CDN 媒体引用 (CDNMedia)
所有媒体类型(图片/语音/文件/视频)通过 CDN 传输,使用 AES-128-ECB 加密:
| 字段 | 类型 | 说明 |
|------|------|------|
| `encrypt_query_param` | `string?` | CDN 下载/上传的加密参数 |
| `aes_key` | `string?` | base64 编码的 AES-128 密钥 |
### CDN 上传流程
1. 计算文件明文大小、MD5以及 AES-128-ECB 加密后的密文大小
2. 如需缩略图(图片/视频),同样计算缩略图的明文和密文参数
3. 调用 `getUploadUrl` 获取 `upload_param`(和 `thumb_upload_param`
4. 使用 AES-128-ECB 加密文件内容PUT 上传到 CDN URL
5. 缩略图同理加密并上传
6. 使用返回的 `encrypt_query_param` 构造 `CDNMedia` 引用,放入 `MessageItem` 发送
> 完整的类型定义见 [`src/api/types.ts`](src/api/types.ts)API 调用实现见 [`src/api/api.ts`](src/api/api.ts)。