@xpert-ai/plugin-community-wechat 0.1.0
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 +353 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +139 -0
- package/dist/lib/constants.d.ts +23 -0
- package/dist/lib/constants.js +23 -0
- package/dist/lib/conversation-user-key.d.ts +13 -0
- package/dist/lib/conversation-user-key.js +28 -0
- package/dist/lib/conversation.service.d.ts +215 -0
- package/dist/lib/conversation.service.js +1179 -0
- package/dist/lib/decorators.d.ts +2 -0
- package/dist/lib/decorators.js +3 -0
- package/dist/lib/entities/index.d.ts +4 -0
- package/dist/lib/entities/index.js +4 -0
- package/dist/lib/entities/wechat-personal-account.entity.d.ts +19 -0
- package/dist/lib/entities/wechat-personal-account.entity.js +83 -0
- package/dist/lib/entities/wechat-personal-conversation-binding.entity.d.ts +14 -0
- package/dist/lib/entities/wechat-personal-conversation-binding.entity.js +65 -0
- package/dist/lib/entities/wechat-personal-message-log.entity.d.ts +27 -0
- package/dist/lib/entities/wechat-personal-message-log.entity.js +108 -0
- package/dist/lib/entities/wechat-personal-trigger-binding.entity.d.ts +17 -0
- package/dist/lib/entities/wechat-personal-trigger-binding.entity.js +71 -0
- package/dist/lib/handoff/index.d.ts +4 -0
- package/dist/lib/handoff/index.js +4 -0
- package/dist/lib/handoff/wechat-personal-chat-callback.processor.d.ts +26 -0
- package/dist/lib/handoff/wechat-personal-chat-callback.processor.js +312 -0
- package/dist/lib/handoff/wechat-personal-chat-dispatch.service.d.ts +26 -0
- package/dist/lib/handoff/wechat-personal-chat-dispatch.service.js +187 -0
- package/dist/lib/handoff/wechat-personal-chat-run-state.service.d.ts +21 -0
- package/dist/lib/handoff/wechat-personal-chat-run-state.service.js +39 -0
- package/dist/lib/handoff/wechat-personal-chat.types.d.ts +69 -0
- package/dist/lib/handoff/wechat-personal-chat.types.js +2 -0
- package/dist/lib/message.d.ts +49 -0
- package/dist/lib/message.js +64 -0
- package/dist/lib/remote-components/wechat-personal-workbench/app.js +1831 -0
- package/dist/lib/tokens.d.ts +1 -0
- package/dist/lib/tokens.js +1 -0
- package/dist/lib/types.d.ts +48 -0
- package/dist/lib/types.js +365 -0
- package/dist/lib/views/wechat-personal-view.provider.d.ts +17 -0
- package/dist/lib/views/wechat-personal-view.provider.js +441 -0
- package/dist/lib/wechat-personal-channel.strategy.d.ts +33 -0
- package/dist/lib/wechat-personal-channel.strategy.js +197 -0
- package/dist/lib/wechat-personal-integration.strategy.d.ts +56 -0
- package/dist/lib/wechat-personal-integration.strategy.js +217 -0
- package/dist/lib/wechat-personal.client.d.ts +29 -0
- package/dist/lib/wechat-personal.client.js +146 -0
- package/dist/lib/wechat-personal.controller.d.ts +50 -0
- package/dist/lib/wechat-personal.controller.js +270 -0
- package/dist/lib/wechat-personal.middleware.d.ts +20 -0
- package/dist/lib/wechat-personal.middleware.js +267 -0
- package/dist/lib/wechat-personal.plugin.d.ts +2 -0
- package/dist/lib/wechat-personal.plugin.js +58 -0
- package/dist/lib/wechat-personal.templates.d.ts +2 -0
- package/dist/lib/wechat-personal.templates.js +100 -0
- package/dist/lib/workflow/index.d.ts +5 -0
- package/dist/lib/workflow/index.js +5 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.service.d.ts +10 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.service.js +39 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.types.d.ts +30 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.types.js +2 -0
- package/dist/lib/workflow/wechat-personal-trigger-flush.processor.d.ts +8 -0
- package/dist/lib/workflow/wechat-personal-trigger-flush.processor.js +39 -0
- package/dist/lib/workflow/wechat-personal-trigger.strategy.d.ts +65 -0
- package/dist/lib/workflow/wechat-personal-trigger.strategy.js +511 -0
- package/dist/lib/workflow/wechat-personal-trigger.types.d.ts +10 -0
- package/dist/lib/workflow/wechat-personal-trigger.types.js +2 -0
- package/dist/xpert-wechat-personal-admin-assistant.yaml +103 -0
- package/dist/xpert-wechat-personal-user-assistant.yaml +127 -0
- package/package.json +79 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { BadRequestException, Body, Controller, Get, Header, HttpCode, Inject, Param, Post, Query, Request } from '@nestjs/common';
|
|
14
|
+
import { INTEGRATION_PERMISSION_SERVICE_TOKEN, RequestContext, runWithRequestContext } from '@xpert-ai/plugin-sdk';
|
|
15
|
+
import { Public } from './decorators.js';
|
|
16
|
+
import { WECHAT_PERSONAL_PROVIDER_KEY } from './constants.js';
|
|
17
|
+
import { WECHAT_PERSONAL_PLUGIN_CONTEXT } from './tokens.js';
|
|
18
|
+
import { WechatPersonalConversationService } from './conversation.service.js';
|
|
19
|
+
import { normalizeString } from './types.js';
|
|
20
|
+
import { WechatPersonalChannelStrategy } from './wechat-personal-channel.strategy.js';
|
|
21
|
+
let WechatPersonalController = class WechatPersonalController {
|
|
22
|
+
constructor(conversation, wechatChannel, pluginContext) {
|
|
23
|
+
this.conversation = conversation;
|
|
24
|
+
this.wechatChannel = wechatChannel;
|
|
25
|
+
this.pluginContext = pluginContext;
|
|
26
|
+
}
|
|
27
|
+
get integrationPermissionService() {
|
|
28
|
+
if (!this._integrationPermissionService) {
|
|
29
|
+
this._integrationPermissionService = this.pluginContext.resolve(INTEGRATION_PERMISSION_SERVICE_TOKEN);
|
|
30
|
+
}
|
|
31
|
+
return this._integrationPermissionService;
|
|
32
|
+
}
|
|
33
|
+
async webhook(integrationId, req, body, querySecret) {
|
|
34
|
+
const integration = await this.readWechatPersonalIntegration(integrationId);
|
|
35
|
+
this.verifyCallbackSecret(integration, req, querySecret);
|
|
36
|
+
const payload = this.parseBodyToObject(body);
|
|
37
|
+
if (!payload) {
|
|
38
|
+
return 'success';
|
|
39
|
+
}
|
|
40
|
+
const event = this.wechatChannel.normalizeWebhookEvent(payload);
|
|
41
|
+
if (!event) {
|
|
42
|
+
return 'success';
|
|
43
|
+
}
|
|
44
|
+
const ctx = {
|
|
45
|
+
integration,
|
|
46
|
+
tenantId: integration.tenantId,
|
|
47
|
+
organizationId: integration.organizationId
|
|
48
|
+
};
|
|
49
|
+
const contextUser = RequestContext.currentUser() ?? req.user ?? {
|
|
50
|
+
id: `wechat-personal:${integration.id}:anonymous`,
|
|
51
|
+
tenantId: integration.tenantId,
|
|
52
|
+
organizationId: integration.organizationId
|
|
53
|
+
};
|
|
54
|
+
const requestHeaders = {
|
|
55
|
+
['tenant-id']: integration.tenantId,
|
|
56
|
+
['organization-id']: integration.organizationId
|
|
57
|
+
};
|
|
58
|
+
if (integration.options?.preferLanguage) {
|
|
59
|
+
requestHeaders.language = integration.options.preferLanguage;
|
|
60
|
+
}
|
|
61
|
+
await new Promise((resolve, reject) => {
|
|
62
|
+
runWithRequestContext({
|
|
63
|
+
user: contextUser,
|
|
64
|
+
headers: requestHeaders
|
|
65
|
+
}, {}, () => {
|
|
66
|
+
this.conversation.handleInboundEvent(event, ctx).then(() => resolve()).catch(reject);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
return 'success';
|
|
70
|
+
}
|
|
71
|
+
async getIntegrationSelectOptions(req, keyword) {
|
|
72
|
+
const options = await this.fetchProviderSelectOptions(req, WECHAT_PERSONAL_PROVIDER_KEY);
|
|
73
|
+
const normalizedKeyword = this.toSafeString(keyword).toLowerCase();
|
|
74
|
+
if (!normalizedKeyword) {
|
|
75
|
+
return options;
|
|
76
|
+
}
|
|
77
|
+
return options.filter((item) => {
|
|
78
|
+
const label = item.label.toLowerCase();
|
|
79
|
+
const value = item.value.toLowerCase();
|
|
80
|
+
const description = this.toSafeString(item.description).toLowerCase();
|
|
81
|
+
return label.includes(normalizedKeyword) || value.includes(normalizedKeyword) || description.includes(normalizedKeyword);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async getCallbackConfig(integrationId) {
|
|
85
|
+
const integration = await this.readWechatPersonalIntegration(integrationId);
|
|
86
|
+
return this.conversation.buildCallbackConfig(integration.id, integration.options?.callbackSecret);
|
|
87
|
+
}
|
|
88
|
+
async registerCallback(integrationId, uuid, body) {
|
|
89
|
+
const integration = await this.readWechatPersonalIntegration(integrationId);
|
|
90
|
+
const callbackConfig = this.conversation.buildCallbackConfig(integration.id, integration.options?.callbackSecret);
|
|
91
|
+
const result = await this.wechatChannel.registerCallback({
|
|
92
|
+
integrationId: integration.id,
|
|
93
|
+
uuid,
|
|
94
|
+
callbackUrl: normalizeString(body?.callbackUrl) || callbackConfig.webhookUrl,
|
|
95
|
+
enabled: body?.enabled !== false
|
|
96
|
+
});
|
|
97
|
+
if (!result.success) {
|
|
98
|
+
throw new BadRequestException(result.error || 'Register wx2.0 callback failed');
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
async sendText(integrationId, body) {
|
|
103
|
+
const integration = await this.readWechatPersonalIntegration(integrationId);
|
|
104
|
+
const result = await this.wechatChannel.sendTextByIntegrationId(integration.id, {
|
|
105
|
+
uuid: body?.uuid,
|
|
106
|
+
contactId: body?.contactId || body?.contactid,
|
|
107
|
+
content: body?.text || body?.content || body?.textcontent || '',
|
|
108
|
+
atUsers: Array.isArray(body?.atUsers) ? body.atUsers : Array.isArray(body?.atusers) ? body.atusers : []
|
|
109
|
+
});
|
|
110
|
+
if (!result.success) {
|
|
111
|
+
throw new BadRequestException(result.error || 'Send wx2.0 text failed');
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
async readWechatPersonalIntegration(integrationId) {
|
|
116
|
+
const integration = await this.integrationPermissionService.read(integrationId, {
|
|
117
|
+
relations: ['tenant']
|
|
118
|
+
});
|
|
119
|
+
if (!integration) {
|
|
120
|
+
throw new BadRequestException(`Integration ${integrationId} not found. Please save the personal WeChat integration first.`);
|
|
121
|
+
}
|
|
122
|
+
if (integration.provider !== WECHAT_PERSONAL_PROVIDER_KEY) {
|
|
123
|
+
throw new BadRequestException(`Integration ${integrationId} is not provider '${WECHAT_PERSONAL_PROVIDER_KEY}'`);
|
|
124
|
+
}
|
|
125
|
+
return integration;
|
|
126
|
+
}
|
|
127
|
+
verifyCallbackSecret(integration, req, querySecret) {
|
|
128
|
+
const expected = this.toSafeString(integration.options?.callbackSecret);
|
|
129
|
+
if (!expected) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const provided = this.toSafeString(querySecret) ||
|
|
133
|
+
this.toSafeString(req.headers['x-wechat-callback-secret']) ||
|
|
134
|
+
this.toSafeString(req.headers['x-xpert-callback-secret']);
|
|
135
|
+
if (provided !== expected) {
|
|
136
|
+
throw new BadRequestException('Invalid personal WeChat callback secret');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async fetchProviderSelectOptions(req, provider) {
|
|
140
|
+
try {
|
|
141
|
+
const host = this.toSafeString(req.get('host'));
|
|
142
|
+
if (!host) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
const protocol = this.toSafeString(req.protocol) || 'http';
|
|
146
|
+
const url = new URL(`${protocol}://${host}/api/integration/select-options`);
|
|
147
|
+
url.searchParams.set('provider', provider);
|
|
148
|
+
const headers = {};
|
|
149
|
+
const authorization = this.toSafeString(req.headers?.authorization);
|
|
150
|
+
const organizationId = this.toSafeString(req.headers?.['organization-id']);
|
|
151
|
+
const tenantId = this.toSafeString(req.headers?.['tenant-id']);
|
|
152
|
+
const language = this.toSafeString(req.headers?.language);
|
|
153
|
+
if (authorization) {
|
|
154
|
+
headers.authorization = authorization;
|
|
155
|
+
}
|
|
156
|
+
if (organizationId) {
|
|
157
|
+
headers['organization-id'] = organizationId;
|
|
158
|
+
}
|
|
159
|
+
if (tenantId) {
|
|
160
|
+
headers['tenant-id'] = tenantId;
|
|
161
|
+
}
|
|
162
|
+
if (language) {
|
|
163
|
+
headers.language = language;
|
|
164
|
+
}
|
|
165
|
+
const response = await fetch(url.toString(), {
|
|
166
|
+
method: 'GET',
|
|
167
|
+
headers
|
|
168
|
+
});
|
|
169
|
+
if (!response.ok) {
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
const payload = (await response.json().catch(() => null));
|
|
173
|
+
if (!Array.isArray(payload)) {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
return payload
|
|
177
|
+
.map((item) => (item && typeof item === 'object' ? item : null))
|
|
178
|
+
.filter((item) => Boolean(item))
|
|
179
|
+
.map((item) => ({
|
|
180
|
+
value: this.toSafeString(item.value),
|
|
181
|
+
label: this.toSafeString(item.label) || this.toSafeString(item.value),
|
|
182
|
+
description: this.toSafeString(item.description) || undefined,
|
|
183
|
+
icon: this.toSafeString(item.icon) || undefined
|
|
184
|
+
}))
|
|
185
|
+
.filter((item) => Boolean(item.value));
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
parseBodyToObject(body) {
|
|
192
|
+
if (!body) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
if (typeof body === 'string') {
|
|
196
|
+
const text = body.trim();
|
|
197
|
+
if (!text) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
return JSON.parse(text);
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (typeof body === 'object') {
|
|
208
|
+
return body;
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
toSafeString(value) {
|
|
213
|
+
if (Array.isArray(value)) {
|
|
214
|
+
return this.toSafeString(value[0]);
|
|
215
|
+
}
|
|
216
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
__decorate([
|
|
220
|
+
Public(),
|
|
221
|
+
Post('webhook/:id'),
|
|
222
|
+
HttpCode(200),
|
|
223
|
+
Header('Content-Type', 'text/plain; charset=utf-8'),
|
|
224
|
+
__param(0, Param('id')),
|
|
225
|
+
__param(1, Request()),
|
|
226
|
+
__param(2, Body()),
|
|
227
|
+
__param(3, Query('secret')),
|
|
228
|
+
__metadata("design:type", Function),
|
|
229
|
+
__metadata("design:paramtypes", [String, Object, Object, String]),
|
|
230
|
+
__metadata("design:returntype", Promise)
|
|
231
|
+
], WechatPersonalController.prototype, "webhook", null);
|
|
232
|
+
__decorate([
|
|
233
|
+
Get('integration-select-options'),
|
|
234
|
+
__param(0, Request()),
|
|
235
|
+
__param(1, Query('keyword')),
|
|
236
|
+
__metadata("design:type", Function),
|
|
237
|
+
__metadata("design:paramtypes", [Object, String]),
|
|
238
|
+
__metadata("design:returntype", Promise)
|
|
239
|
+
], WechatPersonalController.prototype, "getIntegrationSelectOptions", null);
|
|
240
|
+
__decorate([
|
|
241
|
+
Get(':integrationId/callback-config'),
|
|
242
|
+
__param(0, Param('integrationId')),
|
|
243
|
+
__metadata("design:type", Function),
|
|
244
|
+
__metadata("design:paramtypes", [String]),
|
|
245
|
+
__metadata("design:returntype", Promise)
|
|
246
|
+
], WechatPersonalController.prototype, "getCallbackConfig", null);
|
|
247
|
+
__decorate([
|
|
248
|
+
Post(':integrationId/accounts/:uuid/register-callback'),
|
|
249
|
+
__param(0, Param('integrationId')),
|
|
250
|
+
__param(1, Param('uuid')),
|
|
251
|
+
__param(2, Body()),
|
|
252
|
+
__metadata("design:type", Function),
|
|
253
|
+
__metadata("design:paramtypes", [String, String, Object]),
|
|
254
|
+
__metadata("design:returntype", Promise)
|
|
255
|
+
], WechatPersonalController.prototype, "registerCallback", null);
|
|
256
|
+
__decorate([
|
|
257
|
+
Post(':integrationId/send-text'),
|
|
258
|
+
__param(0, Param('integrationId')),
|
|
259
|
+
__param(1, Body()),
|
|
260
|
+
__metadata("design:type", Function),
|
|
261
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
262
|
+
__metadata("design:returntype", Promise)
|
|
263
|
+
], WechatPersonalController.prototype, "sendText", null);
|
|
264
|
+
WechatPersonalController = __decorate([
|
|
265
|
+
Controller('wechat-personal'),
|
|
266
|
+
__param(2, Inject(WECHAT_PERSONAL_PLUGIN_CONTEXT)),
|
|
267
|
+
__metadata("design:paramtypes", [WechatPersonalConversationService,
|
|
268
|
+
WechatPersonalChannelStrategy, Object])
|
|
269
|
+
], WechatPersonalController);
|
|
270
|
+
export { WechatPersonalController };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TAgentMiddlewareMeta } from '@xpert-ai/contracts';
|
|
2
|
+
import { AgentMiddleware, IAgentMiddlewareContext, IAgentMiddlewareStrategy, PromiseOrValue } from '@xpert-ai/plugin-sdk';
|
|
3
|
+
import { WechatPersonalConversationService } from './conversation.service.js';
|
|
4
|
+
import { WechatPersonalChannelStrategy } from './wechat-personal-channel.strategy.js';
|
|
5
|
+
type WechatPersonalRuntimeMiddlewareOptions = {
|
|
6
|
+
integrationId?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class WechatPersonalRuntimeMiddleware implements IAgentMiddlewareStrategy<WechatPersonalRuntimeMiddlewareOptions> {
|
|
9
|
+
private readonly conversationService;
|
|
10
|
+
private readonly wechatChannel;
|
|
11
|
+
readonly meta: TAgentMiddlewareMeta;
|
|
12
|
+
constructor(conversationService: WechatPersonalConversationService, wechatChannel: WechatPersonalChannelStrategy);
|
|
13
|
+
createMiddleware(options: WechatPersonalRuntimeMiddlewareOptions, context: IAgentMiddlewareContext): PromiseOrValue<AgentMiddleware>;
|
|
14
|
+
private resolveIntegrationId;
|
|
15
|
+
private safeJson;
|
|
16
|
+
private success;
|
|
17
|
+
private error;
|
|
18
|
+
private missingIntegrationId;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Injectable } from '@nestjs/common';
|
|
11
|
+
import { tool } from '@langchain/core/tools';
|
|
12
|
+
import { AgentMiddlewareStrategy } from '@xpert-ai/plugin-sdk';
|
|
13
|
+
import { z } from 'zod/v3';
|
|
14
|
+
import { WECHAT_PERSONAL_FEATURE, WECHAT_PERSONAL_GET_CALLBACK_CONFIG_TOOL_NAME, WECHAT_PERSONAL_GET_RUNTIME_STATUS_TOOL_NAME, WECHAT_PERSONAL_ICON, WECHAT_PERSONAL_LIST_ACCOUNTS_TOOL_NAME, WECHAT_PERSONAL_LIST_CONVERSATIONS_TOOL_NAME, WECHAT_PERSONAL_MIDDLEWARE_NAME, WECHAT_PERSONAL_REGISTER_CALLBACK_TOOL_NAME, WECHAT_PERSONAL_RESET_CONVERSATION_TOOL_NAME, WECHAT_PERSONAL_RUNTIME_FEATURE, WECHAT_PERSONAL_SEARCH_MESSAGE_LOGS_TOOL_NAME, WECHAT_PERSONAL_SET_ACCOUNT_ENABLED_TOOL_NAME, WECHAT_PERSONAL_WORKBENCH_FEATURE } from './constants.js';
|
|
15
|
+
import { normalizeString } from './types.js';
|
|
16
|
+
import { WechatPersonalConversationService } from './conversation.service.js';
|
|
17
|
+
import { WechatPersonalChannelStrategy } from './wechat-personal-channel.strategy.js';
|
|
18
|
+
const integrationField = z.string().optional().describe('Personal WeChat integration id. Defaults to the middleware node option.');
|
|
19
|
+
const runtimeStatusSchema = z.object({
|
|
20
|
+
integrationId: integrationField
|
|
21
|
+
});
|
|
22
|
+
const callbackConfigSchema = z.object({
|
|
23
|
+
integrationId: integrationField
|
|
24
|
+
});
|
|
25
|
+
const listAccountsSchema = z.object({
|
|
26
|
+
integrationId: integrationField,
|
|
27
|
+
search: z.string().optional().describe('Keyword for uuid, owner wxid, display name, status or last error.'),
|
|
28
|
+
page: z.number().int().min(1).optional().describe('Page number. Defaults to 1.'),
|
|
29
|
+
pageSize: z.number().int().min(1).max(100).optional().describe('Page size. Defaults to 50.')
|
|
30
|
+
});
|
|
31
|
+
const listConversationsSchema = z.object({
|
|
32
|
+
integrationId: integrationField,
|
|
33
|
+
search: z.string().optional().describe('Keyword for account uuid, contact id, sender id, xpert id or conversation id.'),
|
|
34
|
+
page: z.number().int().min(1).optional().describe('Page number. Defaults to 1.'),
|
|
35
|
+
pageSize: z.number().int().min(1).max(100).optional().describe('Page size. Defaults to 50.')
|
|
36
|
+
});
|
|
37
|
+
const searchMessageLogsSchema = z.object({
|
|
38
|
+
integrationId: integrationField,
|
|
39
|
+
direction: z.enum(['inbound', 'outbound', 'system']).optional().describe('Message direction filter.'),
|
|
40
|
+
status: z.enum(['received', 'dispatched', 'sent', 'skipped', 'failed']).optional().describe('Message status filter.'),
|
|
41
|
+
search: z.string().optional().describe('Keyword for contact, sender, message id, content, error or conversation id.'),
|
|
42
|
+
page: z.number().int().min(1).optional().describe('Page number. Defaults to 1.'),
|
|
43
|
+
pageSize: z.number().int().min(1).max(100).optional().describe('Page size. Defaults to 50.')
|
|
44
|
+
});
|
|
45
|
+
const resetConversationSchema = z.object({
|
|
46
|
+
integrationId: integrationField,
|
|
47
|
+
bindingId: z.string().min(1).describe('Conversation binding id returned by wechat_personal_list_conversations.')
|
|
48
|
+
});
|
|
49
|
+
const registerCallbackSchema = z.object({
|
|
50
|
+
integrationId: integrationField,
|
|
51
|
+
uuid: z.string().min(1).describe('wx2.0 account uuid/key.'),
|
|
52
|
+
callbackUrl: z.string().optional().describe('Optional callback URL. Defaults to the Xpert webhook URL.'),
|
|
53
|
+
enabled: z.boolean().optional().describe('Whether the wx2.0 per-account callback should be enabled. Defaults to true.')
|
|
54
|
+
});
|
|
55
|
+
const setAccountEnabledSchema = z.object({
|
|
56
|
+
integrationId: integrationField,
|
|
57
|
+
uuid: z.string().min(1).describe('wx2.0 account uuid/key.'),
|
|
58
|
+
enabled: z.boolean().describe('Whether this account should accept inbound callbacks.')
|
|
59
|
+
});
|
|
60
|
+
let WechatPersonalRuntimeMiddleware = class WechatPersonalRuntimeMiddleware {
|
|
61
|
+
constructor(conversationService, wechatChannel) {
|
|
62
|
+
this.conversationService = conversationService;
|
|
63
|
+
this.wechatChannel = wechatChannel;
|
|
64
|
+
this.meta = {
|
|
65
|
+
name: WECHAT_PERSONAL_MIDDLEWARE_NAME,
|
|
66
|
+
label: {
|
|
67
|
+
en_US: 'Personal WeChat Runtime',
|
|
68
|
+
zh_Hans: '个人微信运行时'
|
|
69
|
+
},
|
|
70
|
+
description: {
|
|
71
|
+
en_US: 'Expose Personal WeChat workbench discovery and runtime management tools to an assistant.',
|
|
72
|
+
zh_Hans: '为助手暴露个人微信工作台发现能力和运行时管理工具。'
|
|
73
|
+
},
|
|
74
|
+
icon: {
|
|
75
|
+
type: 'svg',
|
|
76
|
+
value: WECHAT_PERSONAL_ICON,
|
|
77
|
+
color: '#16a34a'
|
|
78
|
+
},
|
|
79
|
+
features: [WECHAT_PERSONAL_FEATURE, WECHAT_PERSONAL_RUNTIME_FEATURE, WECHAT_PERSONAL_WORKBENCH_FEATURE],
|
|
80
|
+
configSchema: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
integrationId: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
title: {
|
|
86
|
+
en_US: 'Personal WeChat Integration',
|
|
87
|
+
zh_Hans: '个人微信集成'
|
|
88
|
+
},
|
|
89
|
+
'x-ui': {
|
|
90
|
+
component: 'remoteSelect',
|
|
91
|
+
selectUrl: '/api/wechat-personal/integration-select-options'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
required: []
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
createMiddleware(options, context) {
|
|
100
|
+
return {
|
|
101
|
+
name: WECHAT_PERSONAL_MIDDLEWARE_NAME,
|
|
102
|
+
tools: [
|
|
103
|
+
tool(async (input) => this.safeJson(async () => {
|
|
104
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
105
|
+
return this.success(integrationId
|
|
106
|
+
? 'Personal WeChat runtime status was returned.'
|
|
107
|
+
: 'Organization Personal WeChat runtime status was returned.', integrationId
|
|
108
|
+
? await this.conversationService.getRuntimeStatus(integrationId)
|
|
109
|
+
: await this.conversationService.getOrganizationRuntimeStatus());
|
|
110
|
+
}), {
|
|
111
|
+
name: WECHAT_PERSONAL_GET_RUNTIME_STATUS_TOOL_NAME,
|
|
112
|
+
description: 'Get Personal WeChat runtime status: callback URLs, trigger binding, summary counts, recent accounts and recent errors. Use for setup and operations questions.',
|
|
113
|
+
schema: runtimeStatusSchema
|
|
114
|
+
}),
|
|
115
|
+
tool(async (input) => this.safeJson(async () => {
|
|
116
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
117
|
+
if (!integrationId) {
|
|
118
|
+
return this.success('Organization Personal WeChat callback configurations were returned.', (await this.conversationService.getOrganizationWorkbenchData({ pageSize: 1 })).integrations?.map((integration) => ({
|
|
119
|
+
id: integration.id,
|
|
120
|
+
name: integration.name,
|
|
121
|
+
callbackConfig: integration.callbackConfig
|
|
122
|
+
})) ?? []);
|
|
123
|
+
}
|
|
124
|
+
const integration = await this.wechatChannel.readIntegrationById(integrationId);
|
|
125
|
+
if (!integration) {
|
|
126
|
+
return this.error(`Personal WeChat integration "${integrationId}" was not found.`);
|
|
127
|
+
}
|
|
128
|
+
return this.success('Personal WeChat callback configuration was returned.', this.conversationService.buildCallbackConfig(integration.id, integration.options?.callbackSecret));
|
|
129
|
+
}), {
|
|
130
|
+
name: WECHAT_PERSONAL_GET_CALLBACK_CONFIG_TOOL_NAME,
|
|
131
|
+
description: 'Get the Xpert webhook URL and SetCallback curl template for configuring wx2.0 callbacks.',
|
|
132
|
+
schema: callbackConfigSchema
|
|
133
|
+
}),
|
|
134
|
+
tool(async (input) => this.safeJson(async () => {
|
|
135
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
136
|
+
return this.success(integrationId ? 'Personal WeChat accounts were listed.' : 'Organization Personal WeChat accounts were listed.', integrationId
|
|
137
|
+
? await this.conversationService.listAccounts(integrationId, input)
|
|
138
|
+
: await this.conversationService.listOrganizationAccounts(input));
|
|
139
|
+
}), {
|
|
140
|
+
name: WECHAT_PERSONAL_LIST_ACCOUNTS_TOOL_NAME,
|
|
141
|
+
description: 'List wx2.0 personal WeChat accounts captured by callbacks, including enabled state, online status and recent errors.',
|
|
142
|
+
schema: listAccountsSchema
|
|
143
|
+
}),
|
|
144
|
+
tool(async (input) => this.safeJson(async () => {
|
|
145
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
146
|
+
return this.success(integrationId
|
|
147
|
+
? 'Personal WeChat conversation bindings were listed.'
|
|
148
|
+
: 'Organization Personal WeChat conversation bindings were listed.', integrationId
|
|
149
|
+
? await this.conversationService.listConversations(integrationId, input)
|
|
150
|
+
: await this.conversationService.listOrganizationConversations(input));
|
|
151
|
+
}), {
|
|
152
|
+
name: WECHAT_PERSONAL_LIST_CONVERSATIONS_TOOL_NAME,
|
|
153
|
+
description: 'List Personal WeChat conversation bindings. Use this to find a binding id before resetting a conversation.',
|
|
154
|
+
schema: listConversationsSchema
|
|
155
|
+
}),
|
|
156
|
+
tool(async (input) => this.safeJson(async () => {
|
|
157
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
158
|
+
return this.success(integrationId
|
|
159
|
+
? 'Personal WeChat message logs were searched.'
|
|
160
|
+
: 'Organization Personal WeChat message logs were searched.', integrationId
|
|
161
|
+
? await this.conversationService.searchMessageLogs(integrationId, input)
|
|
162
|
+
: await this.conversationService.searchOrganizationMessageLogs(input));
|
|
163
|
+
}), {
|
|
164
|
+
name: WECHAT_PERSONAL_SEARCH_MESSAGE_LOGS_TOOL_NAME,
|
|
165
|
+
description: 'Search inbound, outbound and system Personal WeChat message logs for diagnostics and audit questions.',
|
|
166
|
+
schema: searchMessageLogsSchema
|
|
167
|
+
}),
|
|
168
|
+
tool(async (input) => this.safeJson(async () => {
|
|
169
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
170
|
+
if (!integrationId) {
|
|
171
|
+
return this.missingIntegrationId();
|
|
172
|
+
}
|
|
173
|
+
await this.conversationService.restartConversationBinding(integrationId, input.bindingId);
|
|
174
|
+
return this.success('Personal WeChat conversation was reset.', {
|
|
175
|
+
bindingId: input.bindingId
|
|
176
|
+
});
|
|
177
|
+
}), {
|
|
178
|
+
name: WECHAT_PERSONAL_RESET_CONVERSATION_TOOL_NAME,
|
|
179
|
+
description: 'Reset one Personal WeChat conversation binding by binding id so the next inbound message starts a fresh Agent conversation.',
|
|
180
|
+
schema: resetConversationSchema
|
|
181
|
+
}),
|
|
182
|
+
tool(async (input) => this.safeJson(async () => {
|
|
183
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
184
|
+
if (!integrationId) {
|
|
185
|
+
return this.missingIntegrationId();
|
|
186
|
+
}
|
|
187
|
+
const integration = await this.wechatChannel.readIntegrationById(integrationId);
|
|
188
|
+
if (!integration) {
|
|
189
|
+
return this.error(`Personal WeChat integration "${integrationId}" was not found.`);
|
|
190
|
+
}
|
|
191
|
+
const callbackConfig = this.conversationService.buildCallbackConfig(integration.id, integration.options?.callbackSecret);
|
|
192
|
+
const result = await this.wechatChannel.registerCallback({
|
|
193
|
+
integrationId: integration.id,
|
|
194
|
+
uuid: input.uuid,
|
|
195
|
+
callbackUrl: normalizeString(input.callbackUrl) || callbackConfig.webhookUrl,
|
|
196
|
+
enabled: input.enabled !== false
|
|
197
|
+
});
|
|
198
|
+
return result.success
|
|
199
|
+
? this.success('wx2.0 SetCallback registration succeeded.', result)
|
|
200
|
+
: this.error(result.error || 'wx2.0 SetCallback registration failed.', result);
|
|
201
|
+
}), {
|
|
202
|
+
name: WECHAT_PERSONAL_REGISTER_CALLBACK_TOOL_NAME,
|
|
203
|
+
description: 'Register or update a wx2.0 per-account callback for a known account uuid/key. This is an administrative setup action.',
|
|
204
|
+
schema: registerCallbackSchema
|
|
205
|
+
}),
|
|
206
|
+
tool(async (input) => this.safeJson(async () => {
|
|
207
|
+
const integrationId = await this.resolveIntegrationId(input.integrationId, options, context);
|
|
208
|
+
if (!integrationId) {
|
|
209
|
+
return this.missingIntegrationId();
|
|
210
|
+
}
|
|
211
|
+
await this.conversationService.setAccountEnabled(integrationId, input.uuid, input.enabled);
|
|
212
|
+
return this.success('Personal WeChat account enabled state was updated.', {
|
|
213
|
+
uuid: input.uuid,
|
|
214
|
+
enabled: input.enabled
|
|
215
|
+
});
|
|
216
|
+
}), {
|
|
217
|
+
name: WECHAT_PERSONAL_SET_ACCOUNT_ENABLED_TOOL_NAME,
|
|
218
|
+
description: 'Enable or disable inbound processing for one wx2.0 personal WeChat account already seen by this integration.',
|
|
219
|
+
schema: setAccountEnabledSchema
|
|
220
|
+
})
|
|
221
|
+
]
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
async resolveIntegrationId(inputIntegrationId, options, context) {
|
|
225
|
+
const nodeOptions = context.node?.options;
|
|
226
|
+
const explicitIntegrationId = normalizeString(inputIntegrationId) ||
|
|
227
|
+
normalizeString(options?.integrationId) ||
|
|
228
|
+
normalizeString(nodeOptions?.integrationId);
|
|
229
|
+
if (explicitIntegrationId) {
|
|
230
|
+
return explicitIntegrationId;
|
|
231
|
+
}
|
|
232
|
+
const xpertId = normalizeString(context.xpertId);
|
|
233
|
+
return xpertId ? this.conversationService.getBoundIntegrationIdForXpert(xpertId) : null;
|
|
234
|
+
}
|
|
235
|
+
async safeJson(factory) {
|
|
236
|
+
try {
|
|
237
|
+
return JSON.stringify(await factory(), null, 2);
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
return JSON.stringify(this.error(err instanceof Error ? err.message : String(err)), null, 2);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
success(message, data) {
|
|
244
|
+
return {
|
|
245
|
+
success: true,
|
|
246
|
+
message,
|
|
247
|
+
data
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
error(message, data) {
|
|
251
|
+
return {
|
|
252
|
+
success: false,
|
|
253
|
+
message,
|
|
254
|
+
data
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
missingIntegrationId() {
|
|
258
|
+
return this.error('Missing Personal WeChat integrationId. Select an integration in the middleware options first.');
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
WechatPersonalRuntimeMiddleware = __decorate([
|
|
262
|
+
Injectable(),
|
|
263
|
+
AgentMiddlewareStrategy(WECHAT_PERSONAL_MIDDLEWARE_NAME),
|
|
264
|
+
__metadata("design:paramtypes", [WechatPersonalConversationService,
|
|
265
|
+
WechatPersonalChannelStrategy])
|
|
266
|
+
], WechatPersonalRuntimeMiddleware);
|
|
267
|
+
export { WechatPersonalRuntimeMiddleware };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { XpertServerPlugin } from '@xpert-ai/plugin-sdk';
|
|
8
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
9
|
+
import { DiscoveryModule } from '@nestjs/core';
|
|
10
|
+
import { WechatPersonalController } from './wechat-personal.controller.js';
|
|
11
|
+
import { WechatPersonalConversationService } from './conversation.service.js';
|
|
12
|
+
import { WechatPersonalClient } from './wechat-personal.client.js';
|
|
13
|
+
import { WechatPersonalChannelStrategy } from './wechat-personal-channel.strategy.js';
|
|
14
|
+
import { WechatPersonalIntegrationStrategy } from './wechat-personal-integration.strategy.js';
|
|
15
|
+
import { WechatPersonalAccountEntity, WechatPersonalConversationBindingEntity, WechatPersonalMessageLogEntity, WechatPersonalTriggerBindingEntity } from './entities/index.js';
|
|
16
|
+
import { WechatPersonalChatCallbackProcessor, WechatPersonalChatDispatchService, WechatPersonalChatRunStateService } from './handoff/index.js';
|
|
17
|
+
import { WechatPersonalTriggerAggregationService, WechatPersonalTriggerFlushProcessor, WechatPersonalTriggerStrategy } from './workflow/index.js';
|
|
18
|
+
import { WechatPersonalViewProvider } from './views/wechat-personal-view.provider.js';
|
|
19
|
+
import { WechatPersonalRuntimeMiddleware } from './wechat-personal.middleware.js';
|
|
20
|
+
const entities = [
|
|
21
|
+
WechatPersonalTriggerBindingEntity,
|
|
22
|
+
WechatPersonalConversationBindingEntity,
|
|
23
|
+
WechatPersonalAccountEntity,
|
|
24
|
+
WechatPersonalMessageLogEntity
|
|
25
|
+
];
|
|
26
|
+
let WechatPersonalPlugin = class WechatPersonalPlugin {
|
|
27
|
+
};
|
|
28
|
+
WechatPersonalPlugin = __decorate([
|
|
29
|
+
XpertServerPlugin({
|
|
30
|
+
imports: [DiscoveryModule, TypeOrmModule.forFeature(entities)],
|
|
31
|
+
entities,
|
|
32
|
+
providers: [
|
|
33
|
+
WechatPersonalClient,
|
|
34
|
+
WechatPersonalConversationService,
|
|
35
|
+
WechatPersonalChannelStrategy,
|
|
36
|
+
WechatPersonalIntegrationStrategy,
|
|
37
|
+
WechatPersonalTriggerStrategy,
|
|
38
|
+
WechatPersonalTriggerAggregationService,
|
|
39
|
+
WechatPersonalTriggerFlushProcessor,
|
|
40
|
+
WechatPersonalChatDispatchService,
|
|
41
|
+
WechatPersonalChatRunStateService,
|
|
42
|
+
WechatPersonalChatCallbackProcessor,
|
|
43
|
+
WechatPersonalRuntimeMiddleware,
|
|
44
|
+
WechatPersonalViewProvider
|
|
45
|
+
],
|
|
46
|
+
controllers: [WechatPersonalController],
|
|
47
|
+
exports: [
|
|
48
|
+
WechatPersonalClient,
|
|
49
|
+
WechatPersonalChannelStrategy,
|
|
50
|
+
WechatPersonalIntegrationStrategy,
|
|
51
|
+
WechatPersonalTriggerStrategy,
|
|
52
|
+
WechatPersonalConversationService,
|
|
53
|
+
WechatPersonalRuntimeMiddleware,
|
|
54
|
+
WechatPersonalViewProvider
|
|
55
|
+
]
|
|
56
|
+
})
|
|
57
|
+
], WechatPersonalPlugin);
|
|
58
|
+
export { WechatPersonalPlugin };
|