@cloudbase/agent-adapter-wx 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -117
- package/dist/index.d.mts +0 -6
- package/dist/index.d.ts +0 -6
- package/dist/index.js +15 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -5,35 +5,62 @@ WeChat adapter for AG-Kit - Forward LLM messages to WeChat platforms
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
✅ **Multi-Platform Support**: WeChat Mini Program, Official Account (Service/Subscription), Enterprise WeChat Customer Service
|
|
8
|
+
✅ **Express Handler**: Ready-to-use `createWxMessageHandler` for Express servers
|
|
9
|
+
✅ **Agent Adapter**: `WeChatAgent` wraps any AG-UI agent with WeChat integration
|
|
10
|
+
✅ **CloudBase History**: `WeChatHistoryManager` with CloudBase database storage
|
|
8
11
|
✅ **Automatic Token Management**: Built-in caching and refresh mechanism
|
|
9
|
-
✅ **Type-Safe**: Full TypeScript support
|
|
10
|
-
✅ **
|
|
11
|
-
✅ **Batch Operations**: Send multiple messages at once
|
|
12
|
-
✅ **Async Support**: Fire-and-forget message sending
|
|
12
|
+
✅ **Type-Safe**: Full TypeScript support
|
|
13
|
+
✅ **Async/Sync Reply**: Supports both sync HTTP response and async message sending
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
16
17
|
```bash
|
|
17
18
|
npm install @cloudbase/agent-adapter-wx
|
|
18
19
|
# or
|
|
19
|
-
yarn add @cloudbase/agent-adapter-wx
|
|
20
|
-
# or
|
|
21
20
|
pnpm add @cloudbase/agent-adapter-wx
|
|
22
21
|
```
|
|
23
22
|
|
|
24
23
|
## Quick Start
|
|
25
24
|
|
|
25
|
+
### Express Server Handler
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import express from "express";
|
|
29
|
+
import { createWxMessageHandler, WeChatAgent } from "@cloudbase/agent-adapter-wx";
|
|
30
|
+
|
|
31
|
+
const app = express();
|
|
32
|
+
app.use(express.json());
|
|
33
|
+
|
|
34
|
+
// Create handler with agent factory
|
|
35
|
+
const wxHandler = createWxMessageHandler(
|
|
36
|
+
async ({ request, options }) => {
|
|
37
|
+
const agent = new WeChatAgent({
|
|
38
|
+
agent: yourBaseAgent,
|
|
39
|
+
wechatConfig: {
|
|
40
|
+
platform: WeChatPlatform.SERVICE,
|
|
41
|
+
appId: process.env.WECHAT_APP_ID!,
|
|
42
|
+
appSecret: process.env.WECHAT_APP_SECRET!,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
return { agent };
|
|
46
|
+
},
|
|
47
|
+
{ logger: console }
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
app.post("/wx/message", wxHandler);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Direct Message Sending
|
|
54
|
+
|
|
26
55
|
```typescript
|
|
27
56
|
import { WeChatSender, WeChatPlatform } from "@cloudbase/agent-adapter-wx";
|
|
28
57
|
|
|
29
|
-
// Initialize sender
|
|
30
58
|
const sender = new WeChatSender({
|
|
31
59
|
platform: WeChatPlatform.MINI_APP,
|
|
32
60
|
appId: "your-app-id",
|
|
33
61
|
appSecret: "your-app-secret",
|
|
34
62
|
});
|
|
35
63
|
|
|
36
|
-
// Send a message
|
|
37
64
|
await sender.send({
|
|
38
65
|
toUser: "user-openid",
|
|
39
66
|
message: {
|
|
@@ -43,38 +70,89 @@ await sender.send({
|
|
|
43
70
|
});
|
|
44
71
|
```
|
|
45
72
|
|
|
46
|
-
##
|
|
73
|
+
## Core Components
|
|
47
74
|
|
|
48
|
-
###
|
|
75
|
+
### createWxMessageHandler
|
|
76
|
+
|
|
77
|
+
Express route handler for WeChat message webhook. Handles the complete message flow:
|
|
78
|
+
|
|
79
|
+
1. Parse incoming WeChat message
|
|
80
|
+
2. Validate message type (text/voice)
|
|
81
|
+
3. Handle retry logic for unverified accounts (11-second rule)
|
|
82
|
+
4. Process "继续" command for async replies
|
|
83
|
+
5. Run agent and return response
|
|
49
84
|
|
|
50
85
|
```typescript
|
|
51
|
-
import {
|
|
86
|
+
import { createWxMessageHandler } from "@cloudbase/agent-adapter-wx";
|
|
52
87
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
platform: WeChatPlatform.MINI_APP,
|
|
56
|
-
appId: process.env.WECHAT_APP_ID!,
|
|
57
|
-
appSecret: process.env.WECHAT_APP_SECRET!,
|
|
88
|
+
const handler = createWxMessageHandler(createAgent, {
|
|
89
|
+
logger: console, // optional logger
|
|
58
90
|
});
|
|
59
91
|
|
|
60
|
-
|
|
61
|
-
|
|
92
|
+
app.post("/wx/callback", handler);
|
|
93
|
+
```
|
|
62
94
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
95
|
+
**Bot ID Resolution Priority:**
|
|
96
|
+
1. `SCF_FUNCTIONNAME` environment variable
|
|
97
|
+
2. Parsed from request URL via `utils.parseBotId()`
|
|
98
|
+
3. Parsed from `HOSTNAME` environment variable
|
|
99
|
+
4. Fallback: `"agent-id"`
|
|
100
|
+
|
|
101
|
+
### WeChatAgent
|
|
102
|
+
|
|
103
|
+
Wraps any AG-UI `AbstractAgent` with WeChat-specific functionality:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { WeChatAgent, WeChatPlatform, WeChatSendMode } from "@cloudbase/agent-adapter-wx";
|
|
107
|
+
|
|
108
|
+
const wechatAgent = new WeChatAgent({
|
|
109
|
+
agent: yourBaseAgent,
|
|
110
|
+
wechatConfig: {
|
|
111
|
+
platform: WeChatPlatform.SERVICE,
|
|
112
|
+
appId: "your-app-id",
|
|
113
|
+
appSecret: "your-app-secret",
|
|
114
|
+
sendMode: WeChatSendMode.AITOOLS, // or WeChatSendMode.LOCAL
|
|
69
115
|
},
|
|
70
|
-
recommendQuestions: [
|
|
71
|
-
"What about tomorrow?",
|
|
72
|
-
"Show me the forecast",
|
|
73
|
-
"Temperature details",
|
|
74
|
-
],
|
|
116
|
+
recommendQuestions: ["Question 1", "Question 2"],
|
|
75
117
|
});
|
|
76
118
|
```
|
|
77
119
|
|
|
120
|
+
### WeChatHistoryManager
|
|
121
|
+
|
|
122
|
+
CloudBase database storage for chat history (singleton pattern):
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { WeChatHistoryManager } from "@cloudbase/agent-adapter-wx";
|
|
126
|
+
|
|
127
|
+
// Initialize (requires TCB_ENV or CLOUDBASE_ENV)
|
|
128
|
+
const historyManager = WeChatHistoryManager.getInstance({
|
|
129
|
+
envId: "your-cloudbase-env", // or set TCB_ENV env var
|
|
130
|
+
collectionName: "wx_chat_history", // default
|
|
131
|
+
botId: "your-bot-id",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Save to history
|
|
135
|
+
await historyManager.saveToHistory({
|
|
136
|
+
messageId: "msg-123",
|
|
137
|
+
role: "user",
|
|
138
|
+
content: "Hello",
|
|
139
|
+
threadId: "conversation-id",
|
|
140
|
+
createdAt: Date.now(),
|
|
141
|
+
metadata: {
|
|
142
|
+
sender: "user-openid",
|
|
143
|
+
triggerSrc: "WXService",
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Get previous reply
|
|
148
|
+
const previous = await historyManager.getPreviousReply(
|
|
149
|
+
"conversation-id",
|
|
150
|
+
"msg-123"
|
|
151
|
+
);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Usage Examples
|
|
155
|
+
|
|
78
156
|
### Enterprise WeChat Customer Service
|
|
79
157
|
|
|
80
158
|
```typescript
|
|
@@ -98,124 +176,94 @@ await sender.send({
|
|
|
98
176
|
### Batch Sending
|
|
99
177
|
|
|
100
178
|
```typescript
|
|
101
|
-
const
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
toUser: "user2",
|
|
108
|
-
message: { content: "Message 2", type: "text" as const },
|
|
109
|
-
},
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
const results = await sender.sendBatch(messages);
|
|
113
|
-
console.log(results);
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Async Sending (Fire and Forget)
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
// Send without waiting for response
|
|
120
|
-
sender.sendAsync({
|
|
121
|
-
toUser: "user-openid",
|
|
122
|
-
message: {
|
|
123
|
-
content: "Notification message",
|
|
124
|
-
type: "text",
|
|
125
|
-
},
|
|
126
|
-
});
|
|
179
|
+
const results = await sender.sendBatch([
|
|
180
|
+
{ toUser: "user1", message: { content: "Message 1", type: "text" } },
|
|
181
|
+
{ toUser: "user2", message: { content: "Message 2", type: "text" } },
|
|
182
|
+
]);
|
|
127
183
|
```
|
|
128
184
|
|
|
129
185
|
## API Reference
|
|
130
186
|
|
|
131
|
-
### WeChatSender
|
|
132
|
-
|
|
133
|
-
#### Constructor
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
new WeChatSender(config: WeChatConfig)
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
#### Methods
|
|
140
|
-
|
|
141
|
-
- `send(options: SendMessageOptions, originMsg?: any): Promise<WeChatAPIResponse>`
|
|
142
|
-
- `sendBatch(messages: SendMessageOptions[]): Promise<WeChatAPIResponse[]>`
|
|
143
|
-
- `sendAsync(options: SendMessageOptions, originMsg?: any): Promise<void>`
|
|
144
|
-
- `clearCache(): void`
|
|
145
|
-
- `getConfig(): WeChatConfig`
|
|
146
|
-
|
|
147
187
|
### Types
|
|
148
188
|
|
|
149
189
|
#### WeChatPlatform
|
|
150
190
|
|
|
151
191
|
```typescript
|
|
152
192
|
enum WeChatPlatform {
|
|
153
|
-
CUSTOM_SERVICE = "WXCustomerService",
|
|
154
|
-
MINI_APP = "
|
|
155
|
-
SERVICE = "WXService",
|
|
156
|
-
SUBSCRIPTION = "WXSubscription",
|
|
193
|
+
CUSTOM_SERVICE = "WXCustomerService", // 企业微信客服
|
|
194
|
+
MINI_APP = "WXMiniApp", // 微信小程序
|
|
195
|
+
SERVICE = "WXService", // 微信服务号
|
|
196
|
+
SUBSCRIPTION = "WXSubscription", // 微信订阅号
|
|
157
197
|
}
|
|
158
198
|
```
|
|
159
199
|
|
|
160
|
-
####
|
|
200
|
+
#### WeChatSendMode
|
|
161
201
|
|
|
162
202
|
```typescript
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
appSecret: string;
|
|
167
|
-
openKfId?: string;
|
|
168
|
-
tokenCacheTTL?: number; // default: 7200000 (2 hours)
|
|
203
|
+
enum WeChatSendMode {
|
|
204
|
+
LOCAL = "local", // Use WeChatSender (local development)
|
|
205
|
+
AITOOLS = "aitools", // Use aitools SDK (cloud function)
|
|
169
206
|
}
|
|
170
207
|
```
|
|
171
208
|
|
|
172
|
-
####
|
|
209
|
+
#### HistoryEntry
|
|
173
210
|
|
|
174
211
|
```typescript
|
|
175
|
-
interface
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
212
|
+
interface HistoryEntry {
|
|
213
|
+
id?: string;
|
|
214
|
+
messageId: string;
|
|
215
|
+
role: "user" | "assistant" | "system";
|
|
216
|
+
content?: string;
|
|
217
|
+
threadId: string;
|
|
218
|
+
createdAt: number;
|
|
219
|
+
botId?: string;
|
|
220
|
+
runId?: string;
|
|
221
|
+
needAsyncReply?: boolean;
|
|
222
|
+
status?: string;
|
|
223
|
+
type?: string;
|
|
224
|
+
metadata?: {
|
|
225
|
+
sender?: string;
|
|
226
|
+
triggerSrc?: string;
|
|
227
|
+
originMsg?: string;
|
|
228
|
+
replyTo?: string;
|
|
229
|
+
reply?: string;
|
|
230
|
+
image?: string;
|
|
231
|
+
recommendQuestions?: string[];
|
|
181
232
|
};
|
|
182
|
-
recommendQuestions?: string[];
|
|
183
|
-
msgId?: string;
|
|
184
233
|
}
|
|
185
234
|
```
|
|
186
235
|
|
|
187
|
-
|
|
236
|
+
### WeChatSender Methods
|
|
188
237
|
|
|
189
|
-
|
|
190
|
-
-
|
|
191
|
-
-
|
|
238
|
+
- `send(options, originMsg?): Promise<WeChatAPIResponse>`
|
|
239
|
+
- `sendBatch(messages): Promise<WeChatAPIResponse[]>`
|
|
240
|
+
- `sendAsync(options, originMsg?): Promise<void>`
|
|
241
|
+
- `clearCache(): void`
|
|
192
242
|
|
|
193
|
-
###
|
|
194
|
-
- Uses customer service message API
|
|
195
|
-
- User must follow the account
|
|
243
|
+
### WeChatHistoryManager Methods
|
|
196
244
|
|
|
197
|
-
|
|
198
|
-
-
|
|
199
|
-
-
|
|
245
|
+
- `getInstance(config?): WeChatHistoryManager` - Get singleton instance
|
|
246
|
+
- `getPreviousReply(threadId, messageId?): Promise<HistoryEntry | null>`
|
|
247
|
+
- `saveToHistory(record): Promise<void>`
|
|
248
|
+
- `updateContent(threadId, messageId, content): Promise<void>`
|
|
200
249
|
|
|
201
|
-
##
|
|
250
|
+
## Environment Variables
|
|
202
251
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
209
|
-
} catch (error) {
|
|
210
|
-
console.error("Failed to send message:", error);
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
## License
|
|
252
|
+
| Variable | Description |
|
|
253
|
+
|----------|-------------|
|
|
254
|
+
| `TCB_ENV` or `CLOUDBASE_ENV` | CloudBase environment ID (required for history) |
|
|
255
|
+
| `SCF_FUNCTIONNAME` | Cloud function name (used as bot ID) |
|
|
256
|
+
| `HOSTNAME` | Container hostname (fallback for bot ID) |
|
|
215
257
|
|
|
216
|
-
|
|
258
|
+
## Platform-Specific Notes
|
|
217
259
|
|
|
218
|
-
|
|
260
|
+
| Platform | Trigger Source | Async Reply |
|
|
261
|
+
|----------|---------------|-------------|
|
|
262
|
+
| Mini Program | `WXMiniApp` | Always async |
|
|
263
|
+
| Service Account | `WXService` | Based on verification |
|
|
264
|
+
| Subscription | `WXSubscription` | Based on verification |
|
|
265
|
+
| Enterprise CS | `WXCustomerService` | Always async |
|
|
219
266
|
|
|
220
|
-
|
|
267
|
+
## License
|
|
221
268
|
|
|
269
|
+
ISC
|
package/dist/index.d.mts
CHANGED
|
@@ -384,11 +384,6 @@ interface WeChatAgentConfig extends AgentConfig {
|
|
|
384
384
|
* Converts agent output to WeChat message format
|
|
385
385
|
*/
|
|
386
386
|
messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;
|
|
387
|
-
/**
|
|
388
|
-
* Optional: Filter which events should trigger WeChat messages
|
|
389
|
-
* Default: only TEXT_MESSAGE_CONTENT events
|
|
390
|
-
*/
|
|
391
|
-
eventFilter?: (event: BaseEvent) => boolean;
|
|
392
387
|
/**
|
|
393
388
|
* Optional: Recommended questions to show after reply
|
|
394
389
|
*/
|
|
@@ -468,7 +463,6 @@ declare class WeChatAgent extends AbstractAgent {
|
|
|
468
463
|
private wechatConfig;
|
|
469
464
|
private _historyManager;
|
|
470
465
|
private messageFormatter;
|
|
471
|
-
private eventFilter;
|
|
472
466
|
private messageBuffer;
|
|
473
467
|
private recommendQuestions?;
|
|
474
468
|
aitools?: aitools.AITools;
|
package/dist/index.d.ts
CHANGED
|
@@ -384,11 +384,6 @@ interface WeChatAgentConfig extends AgentConfig {
|
|
|
384
384
|
* Converts agent output to WeChat message format
|
|
385
385
|
*/
|
|
386
386
|
messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;
|
|
387
|
-
/**
|
|
388
|
-
* Optional: Filter which events should trigger WeChat messages
|
|
389
|
-
* Default: only TEXT_MESSAGE_CONTENT events
|
|
390
|
-
*/
|
|
391
|
-
eventFilter?: (event: BaseEvent) => boolean;
|
|
392
387
|
/**
|
|
393
388
|
* Optional: Recommended questions to show after reply
|
|
394
389
|
*/
|
|
@@ -468,7 +463,6 @@ declare class WeChatAgent extends AbstractAgent {
|
|
|
468
463
|
private wechatConfig;
|
|
469
464
|
private _historyManager;
|
|
470
465
|
private messageFormatter;
|
|
471
|
-
private eventFilter;
|
|
472
466
|
private messageBuffer;
|
|
473
467
|
private recommendQuestions?;
|
|
474
468
|
aitools?: aitools.AITools;
|
package/dist/index.js
CHANGED
|
@@ -350,6 +350,20 @@ function createWxMessageHandler(createAgent, options) {
|
|
|
350
350
|
);
|
|
351
351
|
let skipAI = false;
|
|
352
352
|
let isEnd = false;
|
|
353
|
+
const isUnverifiedAccount = ["WXSubscription", "WXService"].includes(triggerSrc) && !wxVerify;
|
|
354
|
+
if (!isUnverifiedAccount) {
|
|
355
|
+
const existingUserMsg = await agent.getPreviousReply(
|
|
356
|
+
msgData.conversation,
|
|
357
|
+
msgData.recordId
|
|
358
|
+
);
|
|
359
|
+
if (existingUserMsg) {
|
|
360
|
+
logger.info?.("[WX] Duplicate callback detected, skipping:", {
|
|
361
|
+
recordId: msgData.recordId,
|
|
362
|
+
conversation: msgData.conversation
|
|
363
|
+
});
|
|
364
|
+
return res.json({});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
353
367
|
const msgType = extractMsgType(callbackData);
|
|
354
368
|
const validation = validateMessageType(msgType);
|
|
355
369
|
if (!validation.isValid) {
|
|
@@ -925,7 +939,6 @@ var WeChatAgent = class extends import_client2.AbstractAgent {
|
|
|
925
939
|
},
|
|
926
940
|
recommendQuestions: this.recommendQuestions
|
|
927
941
|
}));
|
|
928
|
-
this.eventFilter = config.eventFilter || ((event) => event.type === import_client2.EventType.TEXT_MESSAGE_CONTENT);
|
|
929
942
|
}
|
|
930
943
|
/**
|
|
931
944
|
* Get previous reply from history
|
|
@@ -1088,20 +1101,12 @@ var WeChatAgent = class extends import_client2.AbstractAgent {
|
|
|
1088
1101
|
this.sendToWeChat(errorMessage, input).catch(console.error);
|
|
1089
1102
|
return;
|
|
1090
1103
|
}
|
|
1091
|
-
if (!this.eventFilter(event)) {
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
1104
|
switch (event.type) {
|
|
1105
|
+
case import_client2.EventType.TEXT_MESSAGE_CHUNK:
|
|
1095
1106
|
case import_client2.EventType.TEXT_MESSAGE_CONTENT:
|
|
1096
1107
|
const content = event.delta || event.content || "";
|
|
1097
1108
|
this.messageBuffer += content;
|
|
1098
1109
|
break;
|
|
1099
|
-
case import_client2.EventType.TEXT_MESSAGE_END:
|
|
1100
|
-
if (this.messageBuffer.trim()) {
|
|
1101
|
-
this.sendToWeChat(this.messageBuffer, input).catch(console.error);
|
|
1102
|
-
this.messageBuffer = "";
|
|
1103
|
-
}
|
|
1104
|
-
break;
|
|
1105
1110
|
}
|
|
1106
1111
|
}
|
|
1107
1112
|
/**
|