# @agentor/chat-wecom 中文文档

规范地址：https://npmcn.com/package/%40agentor/chat-wecom/

版本：0\.1\.3
npm 元数据更新时间：2026-08-09T12:43:11.056Z
中文译文更新时间：2026-11-05T20:30:33.409Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40agentor/chat-wecom
原文对照：https://npmcn.com/package/%40agentor/chat-wecom/?lang=original
项目主页：https://github.com/DemoMacro/agentor#readme
源码仓库：https://github.com/DemoMacro/agentor

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：90.7 kB，6 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：chat ^4\.0\.0
- 首次发布：2026-05-17T05:55:45.429Z
- 最新版本发布：2026-08-09T12:43:08.994Z
- 近 30 天下载量：26782（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：7（近 12 个月 7 个）

## 中文简介

企业微信 (WeCom) Chat SDK 适配器，支持 Webhook 群机器人、智能机器人（回调 URL / WebSocket 长连接）和自建应用

## 安装

```sh
npm install @agentor/chat-wecom
```

也可以使用：`pnpm add @agentor/chat-wecom`、`yarn add @agentor/chat-wecom`、`bun add @agentor/chat-wecom`

## README

# @agentor/chat-wecom

[![npm version](https://img.shields.io/npm/v/@agentor/chat-wecom)](https://www.npmjs.com/package/@agentor/chat-wecom) [![npm downloads](https://img.shields.io/npm/dm/@agentor/chat-wecom)](https://www.npmjs.com/package/@agentor/chat-wecom) [![npm license](https://img.shields.io/npm/l/@agentor/chat-wecom)](https://www.npmjs.com/package/@agentor/chat-wecom)

[English](https://npmcn.com/package/%40agentor/chat-wecom/README.md) | **[中文](https://npmcn.com/package/%40agentor/chat-wecom/README.zh-CN.md)**

> [Chat SDK](https://github.com/DemoMacro/agentor) 适配器，用于 [企业微信 (WeCom)](https://developer.work.weixin.qq.com/) 消息集成。

## 功能特性

-   **Webhook (群机器人)** — 通过 Webhook URL 推送消息到群聊
-   **Bot (智能机器人)** — 支持回调 URL 和 WebSocket 长连接两种模式收发消息
-   **App (应用)** — 发送应用消息、接收回调事件、管理 Access Token
-   **富媒体支持** — 图片、语音、视频、文件的上传下载
-   **卡片消息** — 将 Chat SDK 的 `CardElement` 转换为企业微信 Template Card
-   **安全加密** — AES-256-CBC 加解密 + SHA1 签名校验

## 安装

```bash
# Install with npm
npm install chat @agentor/chat-wecom

# Install with yarn
yarn add chat @agentor/chat-wecom

# Install with pnpm
pnpm add chat @agentor/chat-wecom
```

## 快速开始

### Webhook (群机器人)

单向推送消息到群聊：

```typescript
import { createWeComWebhookAdapter } from "@agentor/chat-wecom";

const adapter = createWeComWebhookAdapter({
  key: process.env.WECOM_WEBHOOK_KEY!,
});

const threadId = adapter.encodeThreadId({ key: process.env.WECOM_WEBHOOK_KEY! });
const result = await adapter.postMessage(threadId, "Hello from @agentor/chat-wecom!");
```

### Bot — WebSocket 长连接模式 (智能机器人)

通过 WebSocket 直连企业微信服务，无需公网端点：

```typescript
import { createWeComBotAdapter } from "@agentor/chat-wecom";

const adapter = createWeComBotAdapter({
  botId: process.env.WECOM_BOT_WS_BOT_ID!,
  secret: process.env.WECOM_BOT_WS_SECRET!,
});

await adapter.initialize({
  processMessage: async (_adapter, threadId, factory) => {
    const message = await factory();
    await adapter.postMessage(threadId, message.text);
  },
});

// 断开连接
await adapter.disconnect();
```

### Bot — 回调 URL 模式 (智能机器人)

通过 HTTP 回调接收和回复消息，需要公网可达的端点：

```typescript
import { createWeComBotAdapter } from "@agentor/chat-wecom";

const adapter = createWeComBotAdapter({
  mode: "callback",
  token: process.env.WECOM_BOT_TOKEN!,
  encodingAESKey: process.env.WECOM_BOT_ENCODING_AES_KEY!,
});

await adapter.initialize({
  processMessage: async (_adapter, threadId, factory) => {
    const message = await factory();
    await adapter.postMessage(threadId, message.text);
  },
});

// 在 HTTP 服务器中处理回调
// adapter.handleWebhook(request) → Response
```

### App (应用)

发送应用消息并接收回调事件：

```typescript
import { createWeComAppAdapter } from "@agentor/chat-wecom";

const adapter = createWeComAppAdapter({
  corpId: process.env.WECOM_APP_CORP_ID!,
  corpSecret: process.env.WECOM_APP_CORP_SECRET!,
  agentId: Number(process.env.WECOM_APP_AGENT_ID!),
  token: process.env.WECOM_APP_TOKEN, // 接收回调时必填
  encodingAESKey: process.env.WECOM_APP_ENCODING_AES_KEY, // 接收回调时必填
});

// 发送消息
const threadId = adapter.encodeThreadId({
  corpId: process.env.WECOM_APP_CORP_ID!,
  userId: "user-id",
});
const result = await adapter.postMessage(threadId, "Hello from app!");

// 撤回消息
await adapter.deleteMessage(threadId, result.id);

// 获取 Access Token
const token = await adapter.getAccessToken();
```

## 环境变量

| 变量名 | 必填 | 说明 |
| --- | --- | --- |
| `WECOM_WEBHOOK_KEY` | Webhook | Webhook 群机器人 Key |
| `WECOM_BOT_TOKEN` | Bot (回调) | 回调 Token |
| `WECOM_BOT_ENCODING_AES_KEY` | Bot (回调) | 回调消息加解密 Key (43 字符) |
| `WECOM_BOT_WS_BOT_ID` | Bot (WS) | 智能机器人 ID |
| `WECOM_BOT_WS_SECRET` | Bot (WS) | 智能机器人 Secret |
| `WECOM_APP_CORP_ID` | App | 企业 ID |
| `WECOM_APP_CORP_SECRET` | App | 应用 Secret |
| `WECOM_APP_AGENT_ID` | App | 应用 AgentId |
| `WECOM_APP_TOKEN` | App (回调) | 回调 Token |
| `WECOM_APP_ENCODING_AES_KEY` | App (回调) | 回调消息加解密 Key (43 字符) |

## 配置项

### Webhook (群机器人)

| 选项 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `key` | `string` | — | Webhook Key (必填) |
| `userName` | `string` | `"WeCom Webhook"` | 机器人显示名称 |
| `cardActionUrl` | `string` | 企微官网 | 卡片无链接时 `card_action` 的兜底 URL（见下文「整卡点击」小节） |
| `fetch` | `typeof fetch` | `globalThis.fetch` | 自定义 fetch 函数 |

### Bot (智能机器人)

| 选项 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `mode` | `"callback" | "websocket"` | `"websocket"` | 连接模式 |
| `token` | `string` | — | 回调 Token (callback 模式必填) |
| `encodingAESKey` | `string` | — | 加解密 Key (callback 模式必填) |
| `botId` | `string` | — | 机器人 ID (websocket 模式必填) |
| `secret` | `string` | — | 机器人 Secret (websocket 模式必填) |
| `userName` | `string` | `"WeCom Bot"` | 机器人显示名称 |
| `cardActionUrl` | `string` | 企微官网 | 卡片无链接时 `card_action` 的兜底 URL（见下文「整卡点击」小节） |
| `wsUrl` | `string` | 企业微信默认 | WebSocket 服务地址 |
| `WebSocket` | `typeof WebSocket` | `globalThis.WebSocket` | 自定义 WebSocket 类 |

### App (应用)

| 选项 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `corpId` | `string` | — | 企业 ID (必填) |
| `corpSecret` | `string` | — | 应用 Secret (必填) |
| `agentId` | `number` | — | 应用 AgentId (必填) |
| `token` | `string` | — | 回调 Token (接收回调时必填) |
| `encodingAESKey` | `string` | — | 加解密 Key (接收回调时必填) |
| `userName` | `string` | `"WeCom App"` | 应用显示名称 |
| `cardActionUrl` | `string` | 企微官网 | 卡片无链接时 `card_action` 的兜底 URL（见下文「整卡点击」小节） |
| `fetch` | `typeof fetch` | `globalThis.fetch` | 自定义 fetch 函数 |

## 平台配置

### Webhook (群机器人)

1.  在企业微信群聊中添加「群机器人」
2.  选择「自定义机器人」并创建
3.  复制 Webhook 地址中的 `key` 参数

### Bot (智能机器人)

1.  登录[企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame)
2.  进入「应用管理」→「智能机器人」创建机器人
3.  回调模式：配置回调 URL 并填写 Token 和 EncodingAESKey
4.  WebSocket 模式：获取 Bot ID 和 Secret

### App (应用)

1.  登录[企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame)
2.  进入「应用管理」→「自建」创建应用
3.  获取 CorpId、CorpSecret、AgentId
4.  如需接收回调：在应用详情中配置「接收消息」的 URL、Token、EncodingAESKey

## 消息类型支持

### 接收消息

| 消息类型 | Webhook | Bot (回调/WS) | App |
| --- | --- | --- | --- |
| 文本 (text) | — | ✅ | ✅ |
| 图片 (image) | — | ✅ | ✅ |
| 语音 (voice) | — | ✅ | ✅ |
| 视频 (video) | — | ✅ | ✅ |
| 文件 (file) | — | ✅ | — |
| 位置 (location) | — | — | ✅ |
| 链接 (link) | — | — | ✅ |
| 混合 (mixed) | — | ✅ | — |

> Webhook 为单向推送，不支持接收消息。App 不支持 file 类型回调（企业微信平台限制），视频和语音需通过企业微信内置录制功能发送。

### 发送消息

| 消息类型 | Webhook | Bot (回调) | Bot (WS) | App |
| --- | --- | --- | --- | --- |
| Markdown | ✅ | ✅ | ✅ | ✅ |
| 图片 (image) | ✅ base64 | — | ✅ media\_id | ✅ media\_id |
| 语音 (voice) | ✅ | — | ✅ | ✅ |
| 视频 (video) | — | — | ✅ | ✅ |
| 文件 (file) | ✅ | — | ✅ | ✅ |
| Template Card | ✅ | ✅ | ✅ | ✅ |

> Webhook 和 Bot (回调) 的 Template Card 仅支持 `text_notice` 和 `news_notice` 两种类型。Bot (WS) 和 App 支持全部 5 种卡片类型。Bot (WS) 的媒体消息通过 `respond_msg`（回复消息）发送，主动推送 (`send_msg`) 仅支持 Markdown 和 Template Card。

## 媒体文件处理

### 媒体上传

```typescript
import { uploadAppMedia, uploadWebhookMedia } from "@agentor/chat-wecom";

// 应用消息上传
const mediaId = await uploadAppMedia(accessToken, {
  data: imageBuffer,
  filename: "image.png",
  mimeType: "image/png",
});

// Webhook 上传
const mediaId = await uploadWebhookMedia(webhookKey, {
  data: fileBuffer,
  filename: "document.pdf",
});
```

### 媒体下载

```typescript
import { downloadAppMedia, fetchEncryptedMedia } from "@agentor/chat-wecom";

// 通过 mediaId 下载应用消息媒体
const { data, filename } = await downloadAppMedia(accessToken, mediaId);

// 下载并解密 Bot 加密媒体（需要 aeskey）
const { data, filename } = await fetchEncryptedMedia(url, aeskey);
```

`postMessage` 会自动处理媒体上传流程：传入 `FileUpload` 时，先上传获取 `media_id`，再发送对应类型的媒体消息。

## 卡片消息

支持将 Chat SDK 的 `CardElement` 自动转换为企业微信 Template Card（5 种卡片类型）：

| 卡片类型 | 说明 |
| --- | --- |
| `text_notice` | 文本通知 |
| `news_notice` | 图文通知 |
| `button_interaction` | 按钮交互 |
| `vote_interaction` | 投票交互 |
| `multiple_interaction` | 多选交互 |

卡片类型根据 `CardElement` 内容自动推断：

-   包含多选/下拉 → `multiple_interaction`
-   包含单选 → `vote_interaction`
-   包含按钮 → `button_interaction`
-   包含图片 → `news_notice`
-   默认 → `text_notice`

### 整卡点击（card\_action）

企业微信要求 `text_notice` / `news_notice` 的 `card_action`（整卡点击跳转）**必填且必须是跳转**，`button_interaction` 则**可选**。由于 `CardElement` 没有「整卡链接」字段，`card_action` 的 URL 按以下优先级解析：

1.  卡片的第一个链接（`LinkElement` / `LinkButtonElement`）
2.  头部图片（`imageUrl`）
3.  适配器的 `cardActionUrl` 配置
4.  内置默认（`https://work.weixin.qq.com`）

`button_interaction` 在卡片无链接/图片时省略 `card_action`（整卡不可点击）；`text_notice` / `news_notice` 始终设置 `card_action`（必填），无链接时回退到 `cardActionUrl` 或内置默认。

```typescript
import type { CardElement } from "chat";

const card: CardElement = {
  type: "card",
  title: "审批通知",
  subtitle: "请审批以下申请",
  children: [
    {
      type: "fields",
      children: [{ type: "field", label: "申请人", value: "张三" }],
    },
    {
      type: "actions",
      children: [
        { type: "button", label: "同意", style: "primary", id: "approve" },
        { type: "button", label: "拒绝", style: "danger", id: "reject" },
      ],
    },
  ],
};

await adapter.postMessage(threadId, card);
```

### 卡片按钮回调闭环

`button_interaction` / `vote_interaction` / `multiple_interaction` 卡片的按钮点击，以 chat-sdk 标准的交互动作接入：用户点击后企业微信回调 `template_card_event`，适配器解析后调用 `chat.processAction`，`ButtonElement.id` 映射为 `ActionEvent.actionId`，用 `chat.onAction(actionId, handler)` 响应。

> 仅 **App（应用）** 模式支持按钮回调（Webhook 群机器人、Bot 模式无交互回调）。

回调 XML 中的 `ResponseCode`（72 小时有效、一次性）用于 `updateTemplateCard` 更新卡片状态（如按钮变「已处理」）。发送卡片时 `/message/send` 响应也会返回 `response_code`，二者均可用于更新。

```typescript
import { isWeComAppAdapter, type WeComAppCallbackMessage } from "@agentor/chat-wecom";

// 1. 注册按钮点击处理器（actionId = ButtonElement.id）
chat.onAction("approve", async (event) => {
  const raw = event.raw as WeComAppCallbackMessage;
  console.log(`${event.user.userId} 点击 ${event.actionId}，taskId=${raw.taskId}`);

  // 2. 用回调里的 responseCode 把按钮变为不可点击
  if (isWeComAppAdapter(event.adapter) && raw.responseCode) {
    await event.adapter.updateTemplateCard({
      responseCode: raw.responseCode,
      replaceName: "已同意",
    });
  }
});
```

`updateTemplateCard` 参数：

| 参数 | 说明 |
| --- | --- |
| `responseCode` | 来自回调 `raw.responseCode` 或发送响应 `raw.responseCode` |
| `replaceName` | 按钮变灰替换文案（与 `templateCard` 二选一） |
| `templateCard` | 整卡替换为新卡片（与 `replaceName` 二选一） |
| `userIds` / `partyIds` / `tagIds` / `atAll` | 更新范围，全部缺省时默认 `atAll` 更新所有接收者 |

投票/多选卡片的用户提交结果在 `raw.selectedItems`（`{ questionKey, optionIds }[]`）。

## 加解密

所有回调通信使用 AES-256-CBC 加密和 SHA1 签名校验：

```typescript
import { encrypt, decrypt, calculateSignature, verifySignature } from "@agentor/chat-wecom";

const encrypted = await encrypt(encodingAESKey, "Hello", "receiveId");
const decrypted = await decrypt(encodingAESKey, encrypted, "receiveId");

const signature = await calculateSignature(token, timestamp, nonce, encrypted);
const valid = await verifySignature(token, timestamp, nonce, encrypted, signature);
```

## 不支持的操作

以下操作会抛出 `NotImplementedError`：

-   `editMessage` — 所有适配器均不支持
-   `deleteMessage` — 仅 App 适配器支持
-   `fetchMessages` / `fetchThread` — 不支持
-   `addReaction` / `removeReaction` — 不支持

## License

MIT © [Demo Macro](https://www.demomacro.com/)

## 常见问题

### @agentor/chat-wecom 是什么？

企业微信 \(WeCom\) Chat SDK 适配器，支持 Webhook 群机器人、智能机器人（回调 URL / WebSocket 长连接）和自建应用

### 如何安装 @agentor/chat-wecom？

在项目目录运行 npm install @agentor/chat-wecom，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：chat（^4\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @agentor/chat-wecom 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @agentor/chat-wecom 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @agentor/chat-wecom 可以商用吗？

@agentor/chat-wecom 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @agentor/chat-wecom 的下载量有多少？

根据 npm 官方下载统计，@agentor/chat-wecom 在 2026/10/05 – 2026/11/03 这 30 天内被下载 26,782 次，日均约 893 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @agentor/chat-wecom 还在维护吗？

最新版本 0\.1\.3 发布于 2026/08/09（2 个月前）；至今共发布 7 个版本，其中过去 12 个月发布了 7 个；首次发布于 2026/05/17。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

