@openclaw-china/wecom 2026.3.18 → 2026.3.19
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/dist/index.d.ts +4 -0
- package/dist/index.js +177 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -476,6 +476,10 @@ interface PluginRuntime {
|
|
|
476
476
|
mediaUrl?: string;
|
|
477
477
|
mediaUrls?: string[];
|
|
478
478
|
}) => Promise<void>;
|
|
479
|
+
onSkip?: (payload: unknown, info: {
|
|
480
|
+
kind: string;
|
|
481
|
+
reason: string;
|
|
482
|
+
}) => void;
|
|
479
483
|
onError?: (err: unknown, info: {
|
|
480
484
|
kind: string;
|
|
481
485
|
}) => void;
|
package/dist/index.js
CHANGED
|
@@ -1729,6 +1729,7 @@ var CHANNEL_ORDER = [
|
|
|
1729
1729
|
"wecom",
|
|
1730
1730
|
"wecom-app",
|
|
1731
1731
|
"wecom-kf",
|
|
1732
|
+
"wechat-mp",
|
|
1732
1733
|
"feishu-china"
|
|
1733
1734
|
];
|
|
1734
1735
|
var CHANNEL_DISPLAY_LABELS = {
|
|
@@ -1737,6 +1738,7 @@ var CHANNEL_DISPLAY_LABELS = {
|
|
|
1737
1738
|
wecom: "WeCom\uFF08\u4F01\u4E1A\u5FAE\u4FE1-\u667A\u80FD\u673A\u5668\u4EBA\uFF09",
|
|
1738
1739
|
"wecom-app": "WeCom App\uFF08\u81EA\u5EFA\u5E94\u7528-\u53EF\u63A5\u5165\u5FAE\u4FE1\uFF09",
|
|
1739
1740
|
"wecom-kf": "WeCom KF\uFF08\u5FAE\u4FE1\u5BA2\u670D\uFF09",
|
|
1741
|
+
"wechat-mp": "WeChat MP\uFF08\u5FAE\u4FE1\u516C\u4F17\u53F7\uFF09",
|
|
1740
1742
|
qqbot: "QQBot\uFF08QQ \u673A\u5668\u4EBA\uFF09"
|
|
1741
1743
|
};
|
|
1742
1744
|
var CHANNEL_GUIDE_LINKS = {
|
|
@@ -1745,6 +1747,7 @@ var CHANNEL_GUIDE_LINKS = {
|
|
|
1745
1747
|
wecom: `${GUIDES_BASE}/wecom/configuration.md`,
|
|
1746
1748
|
"wecom-app": `${GUIDES_BASE}/wecom-app/configuration.md`,
|
|
1747
1749
|
"wecom-kf": "https://github.com/BytePioneer-AI/openclaw-china/blob/main/extensions/wecom-kf/README.md",
|
|
1750
|
+
"wechat-mp": `${GUIDES_BASE}/wechat-mp/configuration.md`,
|
|
1748
1751
|
qqbot: `${GUIDES_BASE}/qqbot/configuration.md`
|
|
1749
1752
|
};
|
|
1750
1753
|
var CHINA_CLI_STATE_KEY = /* @__PURE__ */ Symbol.for("@openclaw-china/china-cli-state");
|
|
@@ -1954,7 +1957,9 @@ function isChannelConfigured(cfg, channelId) {
|
|
|
1954
1957
|
case "wecom-app":
|
|
1955
1958
|
return hasTokenPair(channelCfg);
|
|
1956
1959
|
case "wecom-kf":
|
|
1957
|
-
return hasNonEmptyString(channelCfg.corpId) && hasNonEmptyString(channelCfg.
|
|
1960
|
+
return hasNonEmptyString(channelCfg.corpId) && hasNonEmptyString(channelCfg.token) && hasNonEmptyString(channelCfg.encodingAESKey);
|
|
1961
|
+
case "wechat-mp":
|
|
1962
|
+
return hasNonEmptyString(channelCfg.appId) && hasNonEmptyString(channelCfg.token);
|
|
1958
1963
|
default:
|
|
1959
1964
|
return false;
|
|
1960
1965
|
}
|
|
@@ -2215,6 +2220,15 @@ async function configureWecomKf(prompter, cfg) {
|
|
|
2215
2220
|
section("\u914D\u7F6E WeCom KF\uFF08\u5FAE\u4FE1\u5BA2\u670D\uFF09");
|
|
2216
2221
|
showGuideLink("wecom-kf");
|
|
2217
2222
|
const existing = getChannelConfig(cfg, "wecom-kf");
|
|
2223
|
+
Ve(
|
|
2224
|
+
[
|
|
2225
|
+
"\u5411\u5BFC\u987A\u5E8F\uFF1AwebhookPath / token / encodingAESKey / corpId / open_kfid / corpSecret",
|
|
2226
|
+
"\u57FA\u7840\u5FC5\u586B\uFF1AcorpId / token / encodingAESKey / open_kfid",
|
|
2227
|
+
"corpSecret \u4F1A\u4F5C\u4E3A\u6700\u540E\u4E00\u4E2A\u53C2\u6570\u8BE2\u95EE\uFF1B\u9996\u6B21\u63A5\u5165\u53EF\u5148\u7559\u7A7A\uFF0C\u5F85\u56DE\u8C03 URL \u6821\u9A8C\u901A\u8FC7\u5E76\u70B9\u51FB\u201C\u5F00\u59CB\u4F7F\u7528\u201D\u540E\u518D\u8865",
|
|
2228
|
+
"webhookPath \u9ED8\u8BA4\u503C\uFF1A/wecom-kf"
|
|
2229
|
+
].join("\n"),
|
|
2230
|
+
"\u53C2\u6570\u8BF4\u660E"
|
|
2231
|
+
);
|
|
2218
2232
|
const webhookPath = await prompter.askText({
|
|
2219
2233
|
label: "Webhook \u8DEF\u5F84\uFF08\u9ED8\u8BA4 /wecom-kf\uFF09",
|
|
2220
2234
|
defaultValue: toTrimmedString(existing.webhookPath) ?? "/wecom-kf",
|
|
@@ -2235,19 +2249,14 @@ async function configureWecomKf(prompter, cfg) {
|
|
|
2235
2249
|
defaultValue: toTrimmedString(existing.corpId),
|
|
2236
2250
|
required: true
|
|
2237
2251
|
});
|
|
2238
|
-
const corpSecret = await prompter.askSecret({
|
|
2239
|
-
label: "\u5FAE\u4FE1\u5BA2\u670D Secret",
|
|
2240
|
-
existingValue: toTrimmedString(existing.corpSecret),
|
|
2241
|
-
required: true
|
|
2242
|
-
});
|
|
2243
2252
|
const openKfId = await prompter.askText({
|
|
2244
2253
|
label: "open_kfid",
|
|
2245
2254
|
defaultValue: toTrimmedString(existing.openKfId),
|
|
2246
2255
|
required: true
|
|
2247
2256
|
});
|
|
2248
|
-
const
|
|
2249
|
-
label: "\
|
|
2250
|
-
|
|
2257
|
+
const corpSecret = await prompter.askSecret({
|
|
2258
|
+
label: "\u5FAE\u4FE1\u5BA2\u670D Secret\uFF08\u6700\u540E\u586B\u5199\uFF1B\u9996\u6B21\u63A5\u5165\u53EF\u5148\u7559\u7A7A\uFF09",
|
|
2259
|
+
existingValue: toTrimmedString(existing.corpSecret),
|
|
2251
2260
|
required: false
|
|
2252
2261
|
});
|
|
2253
2262
|
return mergeChannelConfig(cfg, "wecom-kf", {
|
|
@@ -2255,8 +2264,72 @@ async function configureWecomKf(prompter, cfg) {
|
|
|
2255
2264
|
token,
|
|
2256
2265
|
encodingAESKey,
|
|
2257
2266
|
corpId,
|
|
2258
|
-
corpSecret,
|
|
2259
2267
|
openKfId,
|
|
2268
|
+
corpSecret: corpSecret || void 0
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
async function configureWechatMp(prompter, cfg) {
|
|
2272
|
+
section("\u914D\u7F6E WeChat MP\uFF08\u5FAE\u4FE1\u516C\u4F17\u53F7\uFF09");
|
|
2273
|
+
showGuideLink("wechat-mp");
|
|
2274
|
+
const existing = getChannelConfig(cfg, "wechat-mp");
|
|
2275
|
+
const webhookPath = await prompter.askText({
|
|
2276
|
+
label: "Webhook \u8DEF\u5F84\uFF08\u9ED8\u8BA4 /wechat-mp\uFF09",
|
|
2277
|
+
defaultValue: toTrimmedString(existing.webhookPath) ?? "/wechat-mp",
|
|
2278
|
+
required: true
|
|
2279
|
+
});
|
|
2280
|
+
const appId = await prompter.askText({
|
|
2281
|
+
label: "\u516C\u4F17\u53F7 appId",
|
|
2282
|
+
defaultValue: toTrimmedString(existing.appId),
|
|
2283
|
+
required: true
|
|
2284
|
+
});
|
|
2285
|
+
const appSecret = await prompter.askSecret({
|
|
2286
|
+
label: "\u516C\u4F17\u53F7 appSecret\uFF08\u4E3B\u52A8\u53D1\u9001\u9700\u8981\uFF09",
|
|
2287
|
+
existingValue: toTrimmedString(existing.appSecret),
|
|
2288
|
+
required: false
|
|
2289
|
+
});
|
|
2290
|
+
const token = await prompter.askSecret({
|
|
2291
|
+
label: "\u670D\u52A1\u5668\u914D\u7F6E token",
|
|
2292
|
+
existingValue: toTrimmedString(existing.token),
|
|
2293
|
+
required: true
|
|
2294
|
+
});
|
|
2295
|
+
const messageMode = await prompter.askSelect(
|
|
2296
|
+
"\u6D88\u606F\u52A0\u89E3\u5BC6\u6A21\u5F0F",
|
|
2297
|
+
[
|
|
2298
|
+
{ value: "plain", label: "plain\uFF08\u660E\u6587\uFF09" },
|
|
2299
|
+
{ value: "safe", label: "safe\uFF08\u5B89\u5168\u6A21\u5F0F\uFF09" },
|
|
2300
|
+
{ value: "compat", label: "compat\uFF08\u517C\u5BB9\u6A21\u5F0F\uFF09" }
|
|
2301
|
+
],
|
|
2302
|
+
toTrimmedString(existing.messageMode) ?? "safe"
|
|
2303
|
+
);
|
|
2304
|
+
let encodingAESKey = toTrimmedString(existing.encodingAESKey);
|
|
2305
|
+
if (messageMode !== "plain") {
|
|
2306
|
+
encodingAESKey = await prompter.askSecret({
|
|
2307
|
+
label: "EncodingAESKey\uFF08safe/compat \u5FC5\u586B\uFF09",
|
|
2308
|
+
existingValue: encodingAESKey,
|
|
2309
|
+
required: true
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
const replyMode = await prompter.askSelect(
|
|
2313
|
+
"\u56DE\u590D\u6A21\u5F0F",
|
|
2314
|
+
[
|
|
2315
|
+
{ value: "passive", label: "passive\uFF085 \u79D2\u5185\u88AB\u52A8\u56DE\u590D\uFF09" },
|
|
2316
|
+
{ value: "active", label: "active\uFF08\u5BA2\u670D\u6D88\u606F\u4E3B\u52A8\u53D1\u9001\uFF09" }
|
|
2317
|
+
],
|
|
2318
|
+
toTrimmedString(existing.replyMode) ?? "passive"
|
|
2319
|
+
);
|
|
2320
|
+
const welcomeText = await prompter.askText({
|
|
2321
|
+
label: "\u6B22\u8FCE\u8BED\uFF08\u53EF\u9009\uFF09",
|
|
2322
|
+
defaultValue: toTrimmedString(existing.welcomeText),
|
|
2323
|
+
required: false
|
|
2324
|
+
});
|
|
2325
|
+
return mergeChannelConfig(cfg, "wechat-mp", {
|
|
2326
|
+
webhookPath,
|
|
2327
|
+
appId,
|
|
2328
|
+
appSecret: appSecret || void 0,
|
|
2329
|
+
token,
|
|
2330
|
+
encodingAESKey: messageMode === "plain" ? void 0 : encodingAESKey,
|
|
2331
|
+
messageMode,
|
|
2332
|
+
replyMode,
|
|
2260
2333
|
welcomeText: welcomeText || void 0
|
|
2261
2334
|
});
|
|
2262
2335
|
}
|
|
@@ -2318,6 +2391,8 @@ async function configureSingleChannel(channel, prompter, cfg) {
|
|
|
2318
2391
|
return configureWecomApp(prompter, cfg);
|
|
2319
2392
|
case "wecom-kf":
|
|
2320
2393
|
return configureWecomKf(prompter, cfg);
|
|
2394
|
+
case "wechat-mp":
|
|
2395
|
+
return configureWechatMp(prompter, cfg);
|
|
2321
2396
|
case "qqbot":
|
|
2322
2397
|
return configureQQBot(prompter, cfg);
|
|
2323
2398
|
default:
|
|
@@ -2459,6 +2534,7 @@ var SUPPORTED_CHANNELS = [
|
|
|
2459
2534
|
"wecom",
|
|
2460
2535
|
"wecom-app",
|
|
2461
2536
|
"wecom-kf",
|
|
2537
|
+
"wechat-mp",
|
|
2462
2538
|
"qqbot"
|
|
2463
2539
|
];
|
|
2464
2540
|
var CHINA_INSTALL_HINT_SHOWN_KEY = /* @__PURE__ */ Symbol.for("@openclaw-china/china-install-hint-shown");
|
|
@@ -7181,6 +7257,8 @@ function normalizeWecomWsCallback(frame) {
|
|
|
7181
7257
|
var MESSAGE_CONTEXT_TTL_MS = 6 * 60 * 1e3;
|
|
7182
7258
|
var EVENT_CONTEXT_TTL_MS = 10 * 1e3;
|
|
7183
7259
|
var STREAM_FINISH_GRACE_MS = 2500;
|
|
7260
|
+
var WECOM_WS_THINKING_MESSAGE = "<think></think>";
|
|
7261
|
+
var WECOM_WS_FINISH_FALLBACK_MESSAGE = "\u2705 \u5904\u7406\u5B8C\u6210\u3002";
|
|
7184
7262
|
var messageContexts = /* @__PURE__ */ new Map();
|
|
7185
7263
|
var eventContexts = /* @__PURE__ */ new Map();
|
|
7186
7264
|
var messageBySessionKey = /* @__PURE__ */ new Map();
|
|
@@ -7342,6 +7420,8 @@ function registerWecomWsMessageContext(params) {
|
|
|
7342
7420
|
pendingAutoImagePaths: [],
|
|
7343
7421
|
createdAt: now2(),
|
|
7344
7422
|
updatedAt: now2(),
|
|
7423
|
+
placeholderContent: "",
|
|
7424
|
+
suppressVisibleFallback: false,
|
|
7345
7425
|
started: false,
|
|
7346
7426
|
finished: false,
|
|
7347
7427
|
queue: Promise.resolve(),
|
|
@@ -7367,6 +7447,7 @@ async function sendWecomWsMessagePlaceholder(params) {
|
|
|
7367
7447
|
finish: false
|
|
7368
7448
|
})
|
|
7369
7449
|
);
|
|
7450
|
+
context.placeholderContent = content;
|
|
7370
7451
|
context.started = true;
|
|
7371
7452
|
context.updatedAt = now2();
|
|
7372
7453
|
});
|
|
@@ -7405,6 +7486,16 @@ function bindWecomWsRouteContext(params) {
|
|
|
7405
7486
|
}
|
|
7406
7487
|
context.updatedAt = now2();
|
|
7407
7488
|
}
|
|
7489
|
+
function markWecomWsMessageContextSkipped(params) {
|
|
7490
|
+
pruneMessageContexts();
|
|
7491
|
+
const key = messageKey(params.accountId.trim(), params.reqId.trim());
|
|
7492
|
+
const context = messageContexts.get(key);
|
|
7493
|
+
if (!context || context.finished) return;
|
|
7494
|
+
const reason = String(params.reason ?? "").trim();
|
|
7495
|
+
if (!reason) return;
|
|
7496
|
+
context.suppressVisibleFallback = true;
|
|
7497
|
+
context.updatedAt = now2();
|
|
7498
|
+
}
|
|
7408
7499
|
async function appendWecomWsActiveStreamChunk(params) {
|
|
7409
7500
|
const result = await appendWecomWsActiveStreamReply({
|
|
7410
7501
|
accountId: params.accountId,
|
|
@@ -7465,6 +7556,7 @@ async function appendWecomWsActiveStreamReply(params) {
|
|
|
7465
7556
|
context.msgItems.push(...acceptedMsgItems);
|
|
7466
7557
|
}
|
|
7467
7558
|
if (chunk.trim()) {
|
|
7559
|
+
context.placeholderContent = "";
|
|
7468
7560
|
context.content = appendStreamSnapshotContent(context.content, chunk);
|
|
7469
7561
|
await context.send(
|
|
7470
7562
|
buildWecomWsRespondMessageCommand({
|
|
@@ -7520,13 +7612,15 @@ async function finishWecomWsMessageContext(params) {
|
|
|
7520
7612
|
const finalContent = errorMessage ? context.content ? `${context.content}
|
|
7521
7613
|
|
|
7522
7614
|
${errorMessage}` : errorMessage : context.content;
|
|
7523
|
-
const
|
|
7615
|
+
const fallbackContent = !finalContent && !context.suppressVisibleFallback && context.placeholderContent === WECOM_WS_THINKING_MESSAGE ? WECOM_WS_FINISH_FALLBACK_MESSAGE : void 0;
|
|
7616
|
+
const finishContent = finalContent || fallbackContent;
|
|
7617
|
+
const sendFinish = context.started || Boolean(finishContent) || context.msgItems.length > 0;
|
|
7524
7618
|
if (sendFinish) {
|
|
7525
7619
|
await context.send(
|
|
7526
7620
|
buildWecomWsRespondMessageCommand({
|
|
7527
7621
|
reqId: context.reqId,
|
|
7528
7622
|
streamId: context.streamId,
|
|
7529
|
-
content:
|
|
7623
|
+
content: finishContent,
|
|
7530
7624
|
finish: true,
|
|
7531
7625
|
msgItems: context.msgItems
|
|
7532
7626
|
})
|
|
@@ -8056,6 +8150,9 @@ async function dispatchWecomMessage(params) {
|
|
|
8056
8150
|
if (!normalized.trim()) return;
|
|
8057
8151
|
await hooks.onChunk(normalized);
|
|
8058
8152
|
},
|
|
8153
|
+
onSkip: (_payload, info) => {
|
|
8154
|
+
hooks.onSkip?.(info);
|
|
8155
|
+
},
|
|
8059
8156
|
onError: (err, info) => {
|
|
8060
8157
|
hooks.onError?.(err);
|
|
8061
8158
|
logger.error(`${info.kind} reply failed: ${String(err)}`);
|
|
@@ -9378,6 +9475,7 @@ async function fetchAndSaveWecomDocMcpConfig(params) {
|
|
|
9378
9475
|
var activeConnections = /* @__PURE__ */ new Map();
|
|
9379
9476
|
var processedMessageIds = /* @__PURE__ */ new Map();
|
|
9380
9477
|
var PROCESSED_MESSAGE_TTL_MS = 10 * 60 * 1e3;
|
|
9478
|
+
var WECOM_WS_SHUTDOWN_GRACE_MS = 1e3;
|
|
9381
9479
|
var activatedTargets = /* @__PURE__ */ new Map();
|
|
9382
9480
|
function getOrCreateConnection(accountId) {
|
|
9383
9481
|
let conn = activeConnections.get(accountId);
|
|
@@ -9493,7 +9591,11 @@ function summarizeWecomReplyFrame(frame) {
|
|
|
9493
9591
|
}
|
|
9494
9592
|
return JSON.stringify(summary);
|
|
9495
9593
|
}
|
|
9496
|
-
function
|
|
9594
|
+
function isExpectedShutdownWsLog(message) {
|
|
9595
|
+
const lowered = message.toLowerCase();
|
|
9596
|
+
return lowered.includes("invalid websocket frame") || lowered.includes("invalid opcode") || lowered.includes("websocket connection closed: code: 1006");
|
|
9597
|
+
}
|
|
9598
|
+
function createSdkLogger(logger, opts) {
|
|
9497
9599
|
return {
|
|
9498
9600
|
debug(message, ...args) {
|
|
9499
9601
|
logger.debug(formatLogMessage(message, args));
|
|
@@ -9502,13 +9604,27 @@ function createSdkLogger(logger) {
|
|
|
9502
9604
|
logger.info(formatLogMessage(message, args));
|
|
9503
9605
|
},
|
|
9504
9606
|
warn(message, ...args) {
|
|
9505
|
-
|
|
9607
|
+
const formatted = formatLogMessage(message, args);
|
|
9608
|
+
if (opts?.isShuttingDown?.() && isExpectedShutdownWsLog(formatted)) {
|
|
9609
|
+
logger.debug(`wecom ws shutdown noise suppressed: ${formatted}`);
|
|
9610
|
+
return;
|
|
9611
|
+
}
|
|
9612
|
+
logger.warn(formatted);
|
|
9506
9613
|
},
|
|
9507
9614
|
error(message, ...args) {
|
|
9508
|
-
|
|
9615
|
+
const formatted = formatLogMessage(message, args);
|
|
9616
|
+
if (opts?.isShuttingDown?.() && isExpectedShutdownWsLog(formatted)) {
|
|
9617
|
+
logger.debug(`wecom ws shutdown noise suppressed: ${formatted}`);
|
|
9618
|
+
return;
|
|
9619
|
+
}
|
|
9620
|
+
logger.error(formatted);
|
|
9509
9621
|
}
|
|
9510
9622
|
};
|
|
9511
9623
|
}
|
|
9624
|
+
function isExpectedShutdownWsError(error) {
|
|
9625
|
+
const message = error.message.toLowerCase();
|
|
9626
|
+
return message.includes("invalid websocket frame") || message.includes("invalid opcode");
|
|
9627
|
+
}
|
|
9512
9628
|
function requireActiveClient(accountId) {
|
|
9513
9629
|
const conn = activeConnections.get(accountId);
|
|
9514
9630
|
if (!conn?.client) {
|
|
@@ -9634,6 +9750,8 @@ async function startWecomWsGateway(opts) {
|
|
|
9634
9750
|
}
|
|
9635
9751
|
conn.promise = new Promise((resolve4, reject) => {
|
|
9636
9752
|
let finished = false;
|
|
9753
|
+
let shuttingDown = false;
|
|
9754
|
+
let shutdownTimer = null;
|
|
9637
9755
|
const client = new WSClient({
|
|
9638
9756
|
botId: account.botId ?? "",
|
|
9639
9757
|
secret: account.secret ?? "",
|
|
@@ -9641,18 +9759,18 @@ async function startWecomWsGateway(opts) {
|
|
|
9641
9759
|
heartbeatInterval: account.heartbeatIntervalMs,
|
|
9642
9760
|
reconnectInterval: account.reconnectInitialDelayMs,
|
|
9643
9761
|
maxReconnectAttempts: -1,
|
|
9644
|
-
logger: createSdkLogger(logger)
|
|
9762
|
+
logger: createSdkLogger(logger, { isShuttingDown: () => shuttingDown })
|
|
9645
9763
|
});
|
|
9646
9764
|
conn.client = client;
|
|
9647
|
-
const
|
|
9765
|
+
const cleanup = (err) => {
|
|
9648
9766
|
if (finished) return;
|
|
9649
9767
|
finished = true;
|
|
9768
|
+
if (shutdownTimer) {
|
|
9769
|
+
clearTimeout(shutdownTimer);
|
|
9770
|
+
shutdownTimer = null;
|
|
9771
|
+
}
|
|
9650
9772
|
abortSignal?.removeEventListener("abort", onAbort);
|
|
9651
9773
|
client.removeAllListeners();
|
|
9652
|
-
try {
|
|
9653
|
-
client.disconnect();
|
|
9654
|
-
} catch {
|
|
9655
|
-
}
|
|
9656
9774
|
clearWecomWsReplyContextsForAccount(account.accountId);
|
|
9657
9775
|
clearActivatedTargetsForAccount(account.accountId);
|
|
9658
9776
|
conn.client = null;
|
|
@@ -9668,9 +9786,27 @@ async function startWecomWsGateway(opts) {
|
|
|
9668
9786
|
if (err) reject(err);
|
|
9669
9787
|
else resolve4();
|
|
9670
9788
|
};
|
|
9789
|
+
const beginShutdown = (err) => {
|
|
9790
|
+
if (finished) return;
|
|
9791
|
+
if (shuttingDown) {
|
|
9792
|
+
return;
|
|
9793
|
+
}
|
|
9794
|
+
shuttingDown = true;
|
|
9795
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
9796
|
+
shutdownTimer = setTimeout(() => {
|
|
9797
|
+
logger.warn(`wecom ws shutdown timed out for account ${account.accountId}; forcing cleanup`);
|
|
9798
|
+
cleanup(err);
|
|
9799
|
+
}, WECOM_WS_SHUTDOWN_GRACE_MS);
|
|
9800
|
+
shutdownTimer.unref?.();
|
|
9801
|
+
try {
|
|
9802
|
+
client.disconnect();
|
|
9803
|
+
} catch (disconnectErr) {
|
|
9804
|
+
cleanup(disconnectErr);
|
|
9805
|
+
}
|
|
9806
|
+
};
|
|
9671
9807
|
const onAbort = () => {
|
|
9672
9808
|
logger.info("abort signal received, stopping wecom ws gateway");
|
|
9673
|
-
|
|
9809
|
+
beginShutdown();
|
|
9674
9810
|
};
|
|
9675
9811
|
const handleMessageCallback = (frame) => {
|
|
9676
9812
|
const callback = normalizeWecomWsCallback(toWecomWsFrame(frame));
|
|
@@ -9717,7 +9853,7 @@ async function startWecomWsGateway(opts) {
|
|
|
9717
9853
|
void sendWecomWsMessagePlaceholder({
|
|
9718
9854
|
accountId: account.accountId,
|
|
9719
9855
|
reqId: callback.reqId,
|
|
9720
|
-
content:
|
|
9856
|
+
content: WECOM_WS_THINKING_MESSAGE
|
|
9721
9857
|
}).catch((err) => {
|
|
9722
9858
|
logger.warn(`wecom ws placeholder ack failed: ${String(err)}`);
|
|
9723
9859
|
});
|
|
@@ -9730,6 +9866,13 @@ async function startWecomWsGateway(opts) {
|
|
|
9730
9866
|
runId: context.runId
|
|
9731
9867
|
});
|
|
9732
9868
|
},
|
|
9869
|
+
onSkip: (info) => {
|
|
9870
|
+
markWecomWsMessageContextSkipped({
|
|
9871
|
+
accountId: account.accountId,
|
|
9872
|
+
reqId: callback.reqId,
|
|
9873
|
+
reason: info.reason
|
|
9874
|
+
});
|
|
9875
|
+
},
|
|
9733
9876
|
onChunk: async (text) => {
|
|
9734
9877
|
await appendWecomWsActiveStreamChunk({
|
|
9735
9878
|
accountId: account.accountId,
|
|
@@ -9919,13 +10062,20 @@ async function startWecomWsGateway(opts) {
|
|
|
9919
10062
|
setStatus?.({
|
|
9920
10063
|
accountId: account.accountId,
|
|
9921
10064
|
mode: "ws",
|
|
9922
|
-
running:
|
|
10065
|
+
running: !shuttingDown,
|
|
9923
10066
|
connectionState: "disconnected",
|
|
9924
10067
|
lastDisconnectAt: Date.now(),
|
|
9925
10068
|
lastDisconnectReason: reason
|
|
9926
10069
|
});
|
|
10070
|
+
if (shuttingDown) {
|
|
10071
|
+
cleanup();
|
|
10072
|
+
}
|
|
9927
10073
|
});
|
|
9928
10074
|
client.on("error", (error) => {
|
|
10075
|
+
if (shuttingDown && isExpectedShutdownWsError(error)) {
|
|
10076
|
+
logger.debug(`wecom ws shutdown noise suppressed: ${error.message}`);
|
|
10077
|
+
return;
|
|
10078
|
+
}
|
|
9929
10079
|
logger.error(`wecom ws sdk error: ${error.message}`);
|
|
9930
10080
|
setStatus?.({
|
|
9931
10081
|
accountId: account.accountId,
|
|
@@ -9935,17 +10085,17 @@ async function startWecomWsGateway(opts) {
|
|
|
9935
10085
|
});
|
|
9936
10086
|
});
|
|
9937
10087
|
conn.stop = () => {
|
|
9938
|
-
|
|
10088
|
+
beginShutdown();
|
|
9939
10089
|
};
|
|
9940
10090
|
if (abortSignal?.aborted) {
|
|
9941
|
-
|
|
10091
|
+
beginShutdown();
|
|
9942
10092
|
return;
|
|
9943
10093
|
}
|
|
9944
10094
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
9945
10095
|
try {
|
|
9946
10096
|
client.connect();
|
|
9947
10097
|
} catch (err) {
|
|
9948
|
-
|
|
10098
|
+
cleanup(err);
|
|
9949
10099
|
}
|
|
9950
10100
|
});
|
|
9951
10101
|
return conn.promise;
|