@openclaw/qqbot 2026.5.26 → 2026.5.27-beta.1
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/api.js +3 -3
- package/dist/{channel-DtN9gbLm.js → channel-C_7BS_5A.js} +15 -8
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{gateway-DuIz6XAh.js → gateway-BdWwKDtj.js} +178 -72
- package/dist/{handler-runtime-I6vCvj2m.js → handler-runtime-CSVOet7I.js} +8 -4
- package/dist/{outbound-Ce2aX078.js → outbound-DHc9KJCp.js} +1 -1
- package/dist/{request-context-D-rKRREP.js → request-context-Dge7ttkg.js} +1 -1
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +2 -0
- package/package.json +5 -5
package/dist/api.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { C as recordMessageReply, E as setOutboundAudioPort, S as getMessageReplyStats, T as OUTBOUND_ERROR_CODES, _ as sendVoice, a as sendText, b as checkMessageReplyLimit, d as buildMediaTarget, f as parseTarget, g as sendVideoMsg, h as sendPhoto, i as sendProactiveMessage, m as sendDocument, n as sendCronMessage, p as resolveOutboundMediaPath, r as sendMedia, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR, x as getMessageReplyConfig, y as MESSAGE_REPLY_LIMIT } from "./outbound-
|
|
1
|
+
import { C as recordMessageReply, E as setOutboundAudioPort, S as getMessageReplyStats, T as OUTBOUND_ERROR_CODES, _ as sendVoice, a as sendText, b as checkMessageReplyLimit, d as buildMediaTarget, f as parseTarget, g as sendVideoMsg, h as sendPhoto, i as sendProactiveMessage, m as sendDocument, n as sendCronMessage, p as resolveOutboundMediaPath, r as sendMedia, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR, x as getMessageReplyConfig, y as MESSAGE_REPLY_LIMIT } from "./outbound-DHc9KJCp.js";
|
|
2
2
|
import { c as listQQBotAccountIds, l as resolveDefaultQQBotAccountId, o as DEFAULT_ACCOUNT_ID, s as applyQQBotAccountConfig, u as resolveQQBotAccount } from "./config-schema-iX2iJzKm.js";
|
|
3
|
-
import { t as qqbotPlugin } from "./channel-
|
|
3
|
+
import { t as qqbotPlugin } from "./channel-C_7BS_5A.js";
|
|
4
4
|
import { C as debugError, l as getAccessToken, w as debugLog, z as formatErrorMessage } from "./runtime-TzkQ0YbR.js";
|
|
5
5
|
import { t as qqbotSetupPlugin } from "./channel.setup-BxGpVkdx.js";
|
|
6
|
-
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-
|
|
6
|
+
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-Dge7ttkg.js";
|
|
7
7
|
import { callGatewayTool } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
8
8
|
//#region extensions/qqbot/src/engine/tools/channel-api.ts
|
|
9
9
|
/**
|
|
@@ -2,12 +2,12 @@ import { c as getPlatformAdapter, t as asOptionalObjectRecord } from "./string-n
|
|
|
2
2
|
import { a as qqbotSetupAdapterShared, c as listQQBotAccountIds, i as qqbotMeta, m as getBridgeLogger, n as qqbotSetupWizard, o as DEFAULT_ACCOUNT_ID$1, p as ensurePlatformAdapter, r as qqbotConfigAdapter, s as applyQQBotAccountConfig, t as qqbotChannelConfigSchema, u as resolveQQBotAccount } from "./config-schema-iX2iJzKm.js";
|
|
3
3
|
import { T as debugWarn, t as getQQBotRuntime, w as debugLog, z as formatErrorMessage } from "./runtime-TzkQ0YbR.js";
|
|
4
4
|
import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-runtime";
|
|
5
|
-
import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-
|
|
5
|
+
import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
|
|
6
6
|
import { createChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
|
|
7
7
|
import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
8
8
|
import { resolveApprovalRequestChannelAccountId, resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
9
9
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
10
|
-
import { resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
10
|
+
import { markImplicitSameChatApprovalAuthorization, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
11
11
|
import { createChannelExecApprovalProfile, isChannelExecApprovalClientEnabledFromConfig, matchesApprovalRequestFilters } from "openclaw/plugin-sdk/approval-client-runtime";
|
|
12
12
|
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
|
|
13
13
|
import * as fs$1 from "node:fs";
|
|
@@ -28,7 +28,13 @@ function buildExecApprovalText(request) {
|
|
|
28
28
|
lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${expiresIn} \u79d2`);
|
|
29
29
|
return lines.join("\n");
|
|
30
30
|
}
|
|
31
|
-
function
|
|
31
|
+
function appendCommandActionLines(lines, actions) {
|
|
32
|
+
const commandActions = actions.filter((action) => (action.kind === "command" || action.decision == null) && typeof action.command === "string" && action.command.trim().length > 0);
|
|
33
|
+
if (commandActions.length === 0) return;
|
|
34
|
+
lines.push("", "🗨️ 命令:");
|
|
35
|
+
for (const action of commandActions) lines.push(`- ${action.label}: ${action.command.trim()}`);
|
|
36
|
+
}
|
|
37
|
+
function buildPluginApprovalText(request, actions = []) {
|
|
32
38
|
const timeoutSec = Math.round((request.request.timeoutMs ?? 12e4) / 1e3);
|
|
33
39
|
const lines = [`${request.request.severity === "critical" ? "🔴" : request.request.severity === "info" ? "🔵" : "🟡"} \u5ba1\u6279\u8bf7\u6c42`, ""];
|
|
34
40
|
lines.push(`\u{1f4cb} ${request.request.title}`);
|
|
@@ -36,6 +42,7 @@ function buildPluginApprovalText(request) {
|
|
|
36
42
|
if (request.request.toolName) lines.push(`\u{1f527} \u5de5\u5177: ${request.request.toolName}`);
|
|
37
43
|
if (request.request.pluginId) lines.push(`\u{1f50c} \u63d2\u4ef6: ${request.request.pluginId}`);
|
|
38
44
|
if (request.request.agentId) lines.push(`\u{1f916} Agent: ${request.request.agentId}`);
|
|
45
|
+
appendCommandActionLines(lines, actions);
|
|
39
46
|
lines.push("", `\u23f1\ufe0f \u8d85\u65f6: ${timeoutSec} \u79d2`);
|
|
40
47
|
return lines.join("\n");
|
|
41
48
|
}
|
|
@@ -241,7 +248,7 @@ const isQQBotExecApprovalApprover = qqbotExecApprovalProfile.isApprover;
|
|
|
241
248
|
const isQQBotExecApprovalAuthorizedSender = qqbotExecApprovalProfile.isAuthorizedSender;
|
|
242
249
|
const shouldHandleQQBotExecApprovalRequest = qqbotExecApprovalProfile.shouldHandleRequest;
|
|
243
250
|
function authorizeQQBotApprovalAction(params) {
|
|
244
|
-
if (resolveQQBotExecApprovalConfig(params) === void 0) return { authorized: true };
|
|
251
|
+
if (resolveQQBotExecApprovalConfig(params) === void 0) return markImplicitSameChatApprovalAuthorization({ authorized: true });
|
|
245
252
|
return (params.approvalKind === "plugin" ? isQQBotExecApprovalApprover(params) : isQQBotExecApprovalAuthorizedSender(params)) ? { authorized: true } : {
|
|
246
253
|
authorized: false,
|
|
247
254
|
reason: "You are not authorized to approve this request."
|
|
@@ -374,7 +381,7 @@ function createQQBotApprovalCapability() {
|
|
|
374
381
|
},
|
|
375
382
|
load: async () => {
|
|
376
383
|
ensurePlatformAdapter();
|
|
377
|
-
return (await import("./handler-runtime-
|
|
384
|
+
return (await import("./handler-runtime-CSVOet7I.js")).qqbotApprovalNativeRuntime;
|
|
378
385
|
}
|
|
379
386
|
})
|
|
380
387
|
});
|
|
@@ -868,7 +875,7 @@ function looksLikeQQBotTarget(id) {
|
|
|
868
875
|
//#region extensions/qqbot/src/channel.ts
|
|
869
876
|
let gatewayModulePromise;
|
|
870
877
|
function loadGatewayModule() {
|
|
871
|
-
gatewayModulePromise ??= import("./gateway-
|
|
878
|
+
gatewayModulePromise ??= import("./gateway-BdWwKDtj.js");
|
|
872
879
|
return gatewayModulePromise;
|
|
873
880
|
}
|
|
874
881
|
function createQQBotSendReceipt(params) {
|
|
@@ -886,7 +893,7 @@ function createQQBotSendReceipt(params) {
|
|
|
886
893
|
async function sendQQBotText(params) {
|
|
887
894
|
await loadGatewayModule();
|
|
888
895
|
const account = resolveQQBotAccount(params.cfg, params.accountId);
|
|
889
|
-
const { sendText } = await import("./outbound-
|
|
896
|
+
const { sendText } = await import("./outbound-DHc9KJCp.js").then((n) => n.t);
|
|
890
897
|
const result = await sendText({
|
|
891
898
|
to: params.to,
|
|
892
899
|
text: params.text,
|
|
@@ -908,7 +915,7 @@ async function sendQQBotText(params) {
|
|
|
908
915
|
async function sendQQBotMedia(params) {
|
|
909
916
|
await loadGatewayModule();
|
|
910
917
|
const account = resolveQQBotAccount(params.cfg, params.accountId);
|
|
911
|
-
const { sendMedia } = await import("./outbound-
|
|
918
|
+
const { sendMedia } = await import("./outbound-DHc9KJCp.js").then((n) => n.t);
|
|
912
919
|
const result = await sendMedia({
|
|
913
920
|
to: params.to,
|
|
914
921
|
text: params.text ?? "",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as qqbotPlugin } from "./channel-
|
|
1
|
+
import { t as qqbotPlugin } from "./channel-C_7BS_5A.js";
|
|
2
2
|
export { qqbotPlugin };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { E as setOutboundAudioPort, _ as sendVoice, c as isMediaPayload, g as sendVideoMsg, h as sendPhoto, l as parseQQBotPayload, m as sendDocument, o as encodePayloadForCron, r as sendMedia, s as isCronReminderPayload, u as normalizeMediaTags, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR } from "./outbound-
|
|
1
|
+
import { E as setOutboundAudioPort, _ as sendVoice, c as isMediaPayload, g as sendVideoMsg, h as sendPhoto, l as parseQQBotPayload, m as sendDocument, o as encodePayloadForCron, r as sendMedia, s as isCronReminderPayload, u as normalizeMediaTags, v as resolveUserFacingMediaError, w as DEFAULT_MEDIA_SEND_ERROR } from "./outbound-DHc9KJCp.js";
|
|
2
2
|
import { c as getPlatformAdapter, i as normalizeOptionalString$1, n as normalizeLowercaseStringOrEmpty$1, o as readStringField, s as sanitizeFileName, t as asOptionalObjectRecord } from "./string-normalize-R_0cKO7Q.js";
|
|
3
3
|
import { f as resolveAccountBase, h as setBridgeLogger, p as ensurePlatformAdapter } from "./config-schema-iX2iJzKm.js";
|
|
4
|
-
import { C as parseApprovalButtonData, a as getQQBotDataDir, d as isWindows, f as normalizePath$1, h as authorizeQQBotApprovalAction, i as getHomeDir, l as getTempDir, m as toGatewayAccount, o as getQQBotDataPath, p as resolveQQBotPayloadLocalFilePath, r as checkSilkWasmAvailable, s as getQQBotMediaDir, u as isLocalPath } from "./channel-
|
|
4
|
+
import { C as parseApprovalButtonData, a as getQQBotDataDir, d as isWindows, f as normalizePath$1, h as authorizeQQBotApprovalAction, i as getHomeDir, l as getTempDir, m as toGatewayAccount, o as getQQBotDataPath, p as resolveQQBotPayloadLocalFilePath, r as checkSilkWasmAvailable, s as getQQBotMediaDir, u as isLocalPath } from "./channel-C_7BS_5A.js";
|
|
5
5
|
import { B as StreamContentType, C as debugError, D as getNextMsgSeq, F as getImageMimeType, H as StreamInputState, I as getMaxUploadSize, N as formatFileSize, R as formatDuration, S as withTokenRetry, T as debugWarn, V as StreamInputMode, _ as sendInputNotify, a as acknowledgeInteraction, b as startBackgroundTokenRefresh, c as createRawInputNotifyFn, d as getMessageApi, f as getPluginUserAgent, g as registerAccount, h as onMessageSent, i as accountToCreds, j as downloadFile, k as openLocalFile, l as getAccessToken, m as initSender, n as getQQBotRuntimeForEngine, o as buildDeliveryTarget, p as initApiConfig, s as clearTokenCache, t as getQQBotRuntime, u as getGatewayUrl, v as sendMedia$1, w as debugLog, x as stopBackgroundTokenRefresh, y as sendText, z as formatErrorMessage } from "./runtime-TzkQ0YbR.js";
|
|
6
|
-
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-
|
|
6
|
+
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-Dge7ttkg.js";
|
|
7
7
|
import { asBoolean, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
|
+
import { isImplicitSameChatApprovalAuthorization } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
8
9
|
import * as fs$1 from "node:fs";
|
|
9
10
|
import fs from "node:fs";
|
|
10
11
|
import * as os$1 from "node:os";
|
|
@@ -18,8 +19,10 @@ import { resolveRuntimeServiceVersion } from "openclaw/plugin-sdk/cli-runtime";
|
|
|
18
19
|
import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
19
20
|
import WebSocket from "ws";
|
|
20
21
|
import { resolveAmbientNodeProxyAgent } from "openclaw/plugin-sdk/extension-shared";
|
|
22
|
+
import { buildChannelInboundEventContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
21
23
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
22
24
|
import { fileURLToPath } from "node:url";
|
|
25
|
+
import { parseAccessGroupAllowFromEntry } from "openclaw/plugin-sdk/access-groups";
|
|
23
26
|
import { createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
24
27
|
import { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-mention-gating";
|
|
25
28
|
import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
@@ -3031,6 +3034,18 @@ function resolveQQBotEffectivePolicies(input) {
|
|
|
3031
3034
|
//#endregion
|
|
3032
3035
|
//#region extensions/qqbot/src/engine/gateway/interaction-handler.ts
|
|
3033
3036
|
/**
|
|
3037
|
+
* INTERACTION_CREATE event handler.
|
|
3038
|
+
*
|
|
3039
|
+
* Handles three interaction branches:
|
|
3040
|
+
*
|
|
3041
|
+
* 1. **Config query** (type=2001) — reads config, ACKs with `claw_cfg`.
|
|
3042
|
+
* 2. **Config update** (type=2002) — writes config, ACKs with updated snapshot.
|
|
3043
|
+
* 3. **Approval button** (other) — ACKs, resolves authorized approval actions.
|
|
3044
|
+
*
|
|
3045
|
+
* Config query/update require `runtime.config`. When unavailable, those
|
|
3046
|
+
* branches fall through to a bare ACK (backward-compatible).
|
|
3047
|
+
*/
|
|
3048
|
+
/**
|
|
3034
3049
|
* Build the canonical `claw_cfg` snapshot returned in interaction ACKs.
|
|
3035
3050
|
*
|
|
3036
3051
|
* Pure function — all resolution helpers live in engine/config/.
|
|
@@ -3138,12 +3153,13 @@ function createInteractionHandler(account, runtime, log, options) {
|
|
|
3138
3153
|
return;
|
|
3139
3154
|
}
|
|
3140
3155
|
handleApprovalButtonInteraction({
|
|
3141
|
-
|
|
3156
|
+
account,
|
|
3142
3157
|
creds,
|
|
3143
3158
|
event,
|
|
3144
3159
|
getActiveCfg: options?.getActiveCfg ?? runtime.config?.current,
|
|
3145
3160
|
log,
|
|
3146
|
-
parsed
|
|
3161
|
+
parsed,
|
|
3162
|
+
resolveCommandAuthorized: options?.resolveCommandAuthorized
|
|
3147
3163
|
});
|
|
3148
3164
|
};
|
|
3149
3165
|
}
|
|
@@ -3161,11 +3177,12 @@ async function handleApprovalButtonInteraction(params) {
|
|
|
3161
3177
|
params.log?.error(`Approval button rejected: active config failed to load: ${err instanceof Error ? err.message : String(err)}`);
|
|
3162
3178
|
return;
|
|
3163
3179
|
}
|
|
3164
|
-
const authorization = authorizeApprovalButtonActor({
|
|
3180
|
+
const authorization = await authorizeApprovalButtonActor({
|
|
3165
3181
|
cfg,
|
|
3166
|
-
|
|
3182
|
+
account: params.account,
|
|
3167
3183
|
event: params.event,
|
|
3168
|
-
approvalKind: resolveApprovalKind(params.parsed.approvalId)
|
|
3184
|
+
approvalKind: resolveApprovalKind(params.parsed.approvalId),
|
|
3185
|
+
resolveCommandAuthorized: params.resolveCommandAuthorized
|
|
3169
3186
|
});
|
|
3170
3187
|
if (!authorization.authorized) {
|
|
3171
3188
|
await acknowledgeApprovalInteraction(params.creds, params.event, params.log, { content: authorization.reason ?? "You are not authorized to approve this request." });
|
|
@@ -3192,23 +3209,42 @@ async function acknowledgeApprovalInteraction(creds, event, log, data) {
|
|
|
3192
3209
|
log?.error(`Interaction ACK failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3193
3210
|
}
|
|
3194
3211
|
}
|
|
3195
|
-
function authorizeApprovalButtonActor(params) {
|
|
3212
|
+
async function authorizeApprovalButtonActor(params) {
|
|
3196
3213
|
const senderIds = resolveApprovalActorSenderIds(params.event);
|
|
3197
|
-
if (senderIds.length === 0)
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3214
|
+
if (senderIds.length === 0) {
|
|
3215
|
+
const result = authorizeQQBotApprovalAction({
|
|
3216
|
+
cfg: params.cfg,
|
|
3217
|
+
accountId: params.account.accountId,
|
|
3218
|
+
senderId: null,
|
|
3219
|
+
approvalKind: params.approvalKind
|
|
3220
|
+
});
|
|
3221
|
+
return result.authorized && isImplicitSameChatApprovalAuthorization(result) ? {
|
|
3222
|
+
authorized: false,
|
|
3223
|
+
reason: "You are not authorized to approve this request."
|
|
3224
|
+
} : result;
|
|
3225
|
+
}
|
|
3203
3226
|
let denial;
|
|
3204
3227
|
for (const senderId of senderIds) {
|
|
3205
3228
|
const result = authorizeQQBotApprovalAction({
|
|
3206
3229
|
cfg: params.cfg,
|
|
3207
|
-
accountId: params.accountId,
|
|
3230
|
+
accountId: params.account.accountId,
|
|
3208
3231
|
senderId,
|
|
3209
3232
|
approvalKind: params.approvalKind
|
|
3210
3233
|
});
|
|
3211
|
-
if (result.authorized)
|
|
3234
|
+
if (result.authorized) {
|
|
3235
|
+
if (!isImplicitSameChatApprovalAuthorization(result) || await isImplicitApprovalButtonActorAuthorized({
|
|
3236
|
+
cfg: params.cfg,
|
|
3237
|
+
account: params.account,
|
|
3238
|
+
event: params.event,
|
|
3239
|
+
senderId,
|
|
3240
|
+
resolveCommandAuthorized: params.resolveCommandAuthorized
|
|
3241
|
+
})) return result;
|
|
3242
|
+
denial ??= {
|
|
3243
|
+
authorized: false,
|
|
3244
|
+
reason: "You are not authorized to approve this request."
|
|
3245
|
+
};
|
|
3246
|
+
continue;
|
|
3247
|
+
}
|
|
3212
3248
|
denial ??= result;
|
|
3213
3249
|
}
|
|
3214
3250
|
return denial ?? {
|
|
@@ -3216,6 +3252,32 @@ function authorizeApprovalButtonActor(params) {
|
|
|
3216
3252
|
reason: "You are not authorized to approve this request."
|
|
3217
3253
|
};
|
|
3218
3254
|
}
|
|
3255
|
+
async function isImplicitApprovalButtonActorAuthorized(params) {
|
|
3256
|
+
const accountConfig = resolveApprovalButtonAccountConfig(params.cfg, params.account.accountId);
|
|
3257
|
+
const authInput = {
|
|
3258
|
+
cfg: params.cfg,
|
|
3259
|
+
accountId: params.account.accountId,
|
|
3260
|
+
senderId: params.senderId,
|
|
3261
|
+
isGroup: Boolean(params.event.group_openid),
|
|
3262
|
+
conversationId: params.event.group_openid ?? params.event.user_openid ?? params.senderId,
|
|
3263
|
+
allowFrom: accountConfig.allowFrom,
|
|
3264
|
+
groupAllowFrom: accountConfig.groupAllowFrom,
|
|
3265
|
+
commandsAllowFrom: resolveQQBotCommandsAllowFrom(params.cfg)
|
|
3266
|
+
};
|
|
3267
|
+
return params.resolveCommandAuthorized ? await params.resolveCommandAuthorized(authInput) : resolveSlashCommandAuth(authInput);
|
|
3268
|
+
}
|
|
3269
|
+
function resolveApprovalButtonAccountConfig(cfg, accountId) {
|
|
3270
|
+
const qqbot = readRecord(readRecord(cfg.channels)?.qqbot);
|
|
3271
|
+
const accounts = readRecord(qqbot?.accounts);
|
|
3272
|
+
if (accountId === "default") return {
|
|
3273
|
+
...qqbot,
|
|
3274
|
+
...readRecord(accounts?.default)
|
|
3275
|
+
};
|
|
3276
|
+
return readRecord(accounts?.[accountId]) ?? {};
|
|
3277
|
+
}
|
|
3278
|
+
function readRecord(value) {
|
|
3279
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3280
|
+
}
|
|
3219
3281
|
function resolveApprovalActorSenderIds(event) {
|
|
3220
3282
|
return uniqueStrings([event.group_member_openid, event.user_openid].flatMap((value) => {
|
|
3221
3283
|
const normalized = typeof value === "string" ? value.trim() : "";
|
|
@@ -5662,6 +5724,17 @@ function resolveResponseTimeoutMs(cfg) {
|
|
|
5662
5724
|
}
|
|
5663
5725
|
//#endregion
|
|
5664
5726
|
//#region extensions/qqbot/src/engine/gateway/outbound-dispatch.ts
|
|
5727
|
+
/**
|
|
5728
|
+
* Outbound dispatcher — manage AI reply delivery, tool fallback, and timeouts.
|
|
5729
|
+
*
|
|
5730
|
+
* Responsibilities:
|
|
5731
|
+
* 1. Build ctxPayload and call runtime.dispatchReply
|
|
5732
|
+
* 2. Tool deliver collection + fallback timeout
|
|
5733
|
+
* 3. Block deliver pipeline (consumeQuoteRef → media tags → structured payload → plain text)
|
|
5734
|
+
* 4. Timeout / error handling
|
|
5735
|
+
*
|
|
5736
|
+
* Separated from gateway.ts for testability and to keep handleMessage thin.
|
|
5737
|
+
*/
|
|
5665
5738
|
const TOOL_ONLY_TIMEOUT = 6e4;
|
|
5666
5739
|
const MAX_TOOL_RENEWALS = 3;
|
|
5667
5740
|
const TOOL_MEDIA_SEND_TIMEOUT = 45e3;
|
|
@@ -5689,7 +5762,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5689
5762
|
};
|
|
5690
5763
|
const sendWithRetry = (sendFn) => sendWithTokenRetry(account.appId, account.clientSecret, sendFn, log, account.accountId);
|
|
5691
5764
|
const sendErrorMessage = (errorText) => sendErrorToTarget(replyCtx, errorText);
|
|
5692
|
-
const ctxPayload = buildCtxPayload(inbound, runtime, cfg);
|
|
5765
|
+
const ctxPayload = await buildCtxPayload(inbound, runtime, cfg);
|
|
5693
5766
|
let hasResponse = false;
|
|
5694
5767
|
let hasBlockResponse = false;
|
|
5695
5768
|
let toolDeliverCount = 0;
|
|
@@ -5783,7 +5856,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5783
5856
|
const cfgWithSession = cfg;
|
|
5784
5857
|
const agentId = inbound.route.agentId ?? "default";
|
|
5785
5858
|
const storePath = runtime.channel.session.resolveStorePath(cfgWithSession.session?.store, { agentId });
|
|
5786
|
-
const dispatchPromise = runtime.channel.
|
|
5859
|
+
const dispatchPromise = runtime.channel.inbound.run({
|
|
5787
5860
|
channel: "qqbot",
|
|
5788
5861
|
accountId: inbound.route.accountId,
|
|
5789
5862
|
raw: inbound,
|
|
@@ -5979,59 +6052,75 @@ function resolveCommandSource(inbound, runtime, cfg) {
|
|
|
5979
6052
|
if (!runtime.channel.commands?.isControlCommandMessage?.(commandBody, cfg)) return;
|
|
5980
6053
|
return "text";
|
|
5981
6054
|
}
|
|
5982
|
-
function buildCtxPayload(inbound, runtime, cfg) {
|
|
6055
|
+
async function buildCtxPayload(inbound, runtime, cfg) {
|
|
5983
6056
|
const { event } = inbound;
|
|
5984
6057
|
const commandSource = resolveCommandSource(inbound, runtime, cfg);
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
} :
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
}
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6058
|
+
const hasImageMedia = inbound.localMediaPaths.length > 0 || inbound.remoteMediaUrls.length > 0;
|
|
6059
|
+
return buildChannelInboundEventContext({
|
|
6060
|
+
finalize: runtime.channel.reply.finalizeInboundContext,
|
|
6061
|
+
channel: "qqbot",
|
|
6062
|
+
accountId: inbound.route.accountId,
|
|
6063
|
+
messageId: event.messageId,
|
|
6064
|
+
timestamp: new Date(event.timestamp).getTime(),
|
|
6065
|
+
from: inbound.fromAddress,
|
|
6066
|
+
sender: {
|
|
6067
|
+
id: event.senderId,
|
|
6068
|
+
name: event.senderName
|
|
6069
|
+
},
|
|
6070
|
+
conversation: {
|
|
6071
|
+
kind: inbound.isGroupChat ? "group" : "direct",
|
|
6072
|
+
id: inbound.peerId
|
|
6073
|
+
},
|
|
6074
|
+
route: {
|
|
6075
|
+
agentId: inbound.route.agentId ?? "main",
|
|
6076
|
+
routeSessionKey: inbound.route.sessionKey,
|
|
6077
|
+
accountId: inbound.route.accountId
|
|
6078
|
+
},
|
|
6079
|
+
reply: { to: inbound.fromAddress },
|
|
6080
|
+
message: {
|
|
6081
|
+
body: inbound.body,
|
|
6082
|
+
bodyForAgent: inbound.agentBody,
|
|
6083
|
+
rawBody: event.content,
|
|
6084
|
+
commandBody: event.content
|
|
6085
|
+
},
|
|
6086
|
+
access: { commands: { authorized: inbound.commandAuthorized } },
|
|
6087
|
+
command: commandSource ? {
|
|
6088
|
+
kind: "text-slash",
|
|
6089
|
+
body: event.content,
|
|
6090
|
+
authorized: inbound.commandAuthorized
|
|
6091
|
+
} : void 0,
|
|
6092
|
+
media: hasImageMedia ? void 0 : inbound.voiceMediaTypes.map((contentType) => ({ contentType })),
|
|
6093
|
+
supplemental: {
|
|
6094
|
+
quote: inbound.replyTo ? {
|
|
6095
|
+
id: inbound.replyTo.id,
|
|
6096
|
+
body: inbound.replyTo.body,
|
|
6097
|
+
sender: inbound.replyTo.sender,
|
|
6098
|
+
isQuote: inbound.replyTo.isQuote
|
|
6099
|
+
} : void 0,
|
|
6100
|
+
groupSystemPrompt: inbound.groupSystemPrompt
|
|
6101
|
+
},
|
|
6102
|
+
extra: {
|
|
6103
|
+
QQChannelId: event.channelId,
|
|
6104
|
+
QQGuildId: event.guildId,
|
|
6105
|
+
QQGroupOpenid: event.groupOpenid,
|
|
6106
|
+
QQVoiceAsrReferAvailable: inbound.hasAsrReferFallback,
|
|
6107
|
+
QQVoiceTranscriptSources: inbound.voiceTranscriptSources,
|
|
6108
|
+
QQVoiceAttachmentPaths: inbound.uniqueVoicePaths,
|
|
6109
|
+
QQVoiceAttachmentUrls: inbound.uniqueVoiceUrls,
|
|
6110
|
+
QQVoiceAsrReferTexts: inbound.uniqueVoiceAsrReferTexts,
|
|
6111
|
+
QQVoiceInputStrategy: "prefer_audio_stt_then_asr_fallback",
|
|
6112
|
+
...commandSource ? { CommandSource: commandSource } : {},
|
|
6113
|
+
...inbound.localMediaPaths.length > 0 ? {
|
|
6114
|
+
MediaPaths: inbound.localMediaPaths,
|
|
6115
|
+
MediaPath: inbound.localMediaPaths[0],
|
|
6116
|
+
MediaTypes: inbound.localMediaTypes,
|
|
6117
|
+
MediaType: inbound.localMediaTypes[0]
|
|
6118
|
+
} : {},
|
|
6119
|
+
...inbound.remoteMediaUrls.length > 0 ? {
|
|
6120
|
+
MediaUrls: inbound.remoteMediaUrls,
|
|
6121
|
+
MediaUrl: inbound.remoteMediaUrls[0]
|
|
6122
|
+
} : {}
|
|
6123
|
+
}
|
|
6035
6124
|
});
|
|
6036
6125
|
}
|
|
6037
6126
|
//#endregion
|
|
@@ -6225,7 +6314,10 @@ async function startGateway$1(ctx) {
|
|
|
6225
6314
|
});
|
|
6226
6315
|
}
|
|
6227
6316
|
};
|
|
6228
|
-
const handleInteraction = createInteractionHandler(account, ctx.runtime, log, {
|
|
6317
|
+
const handleInteraction = createInteractionHandler(account, ctx.runtime, log, {
|
|
6318
|
+
getActiveCfg: () => activeCfgProvider.getActiveCfg(),
|
|
6319
|
+
resolveCommandAuthorized: (params) => adapters.access.resolveSlashCommandAuthorization(params)
|
|
6320
|
+
});
|
|
6229
6321
|
await new GatewayConnection({
|
|
6230
6322
|
account,
|
|
6231
6323
|
abortSignal: ctx.abortSignal,
|
|
@@ -6443,7 +6535,7 @@ function createSdkAccessAdapter() {
|
|
|
6443
6535
|
};
|
|
6444
6536
|
}
|
|
6445
6537
|
async function resolveQQBotSlashCommandAuthorized(params) {
|
|
6446
|
-
const explicitAllowFrom =
|
|
6538
|
+
const explicitAllowFrom = normalizeQQBotCommandAllowFrom(params.commandsAllowFrom ?? (params.isGroup && params.groupAllowFrom && params.groupAllowFrom.length > 0 ? params.groupAllowFrom : params.allowFrom));
|
|
6447
6539
|
if (explicitAllowFrom.length === 0) return false;
|
|
6448
6540
|
return (await createChannelIngressResolver({
|
|
6449
6541
|
channelId: "qqbot",
|
|
@@ -6467,6 +6559,20 @@ async function resolveQQBotSlashCommandAuthorized(params) {
|
|
|
6467
6559
|
command: { modeWhenAccessGroupsOff: "configured" }
|
|
6468
6560
|
})).commandAccess.authorized;
|
|
6469
6561
|
}
|
|
6562
|
+
function normalizeQQBotCommandAllowFrom(rawAllowFrom) {
|
|
6563
|
+
const entries = [];
|
|
6564
|
+
for (const rawEntry of rawAllowFrom ?? []) {
|
|
6565
|
+
const entry = String(rawEntry).trim();
|
|
6566
|
+
if (!entry) continue;
|
|
6567
|
+
if (parseAccessGroupAllowFromEntry(entry)) {
|
|
6568
|
+
entries.push(entry);
|
|
6569
|
+
continue;
|
|
6570
|
+
}
|
|
6571
|
+
const normalized = normalizeQQBotSenderId(entry);
|
|
6572
|
+
if (normalized && normalized !== "*") entries.push(normalized);
|
|
6573
|
+
}
|
|
6574
|
+
return entries;
|
|
6575
|
+
}
|
|
6470
6576
|
//#endregion
|
|
6471
6577
|
//#region extensions/qqbot/src/bridge/gateway.ts
|
|
6472
6578
|
/**
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { m as getBridgeLogger, p as ensurePlatformAdapter, u as resolveQQBotAccount } from "./config-schema-iX2iJzKm.js";
|
|
2
|
-
import { S as buildPluginApprovalText, _ as matchesQQBotApprovalAccount, b as buildApprovalKeyboard, g as isQQBotExecApprovalClientEnabled, v as resolveQQBotExecApprovalConfig, w as resolveApprovalTarget, x as buildExecApprovalText, y as shouldHandleQQBotExecApprovalRequest } from "./channel-
|
|
2
|
+
import { S as buildPluginApprovalText, _ as matchesQQBotApprovalAccount, b as buildApprovalKeyboard, g as isQQBotExecApprovalClientEnabled, v as resolveQQBotExecApprovalConfig, w as resolveApprovalTarget, x as buildExecApprovalText, y as shouldHandleQQBotExecApprovalRequest } from "./channel-C_7BS_5A.js";
|
|
3
3
|
import { d as getMessageApi, i as accountToCreds } from "./runtime-TzkQ0YbR.js";
|
|
4
4
|
import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
5
5
|
import { createChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
6
6
|
//#region extensions/qqbot/src/bridge/approval/handler-runtime.ts
|
|
7
7
|
function isExecRequest(request) {
|
|
8
|
-
return "
|
|
8
|
+
return "command" in request.request;
|
|
9
|
+
}
|
|
10
|
+
function listDecisionActions(actions) {
|
|
11
|
+
return actions.flatMap((action) => action.kind === "decision" && action.decision ? [action.decision] : []);
|
|
9
12
|
}
|
|
10
13
|
function resolveQQTarget(request) {
|
|
11
14
|
const sessionConversation = resolveApprovalRequestSessionConversation({
|
|
@@ -71,8 +74,9 @@ const qqbotApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter({
|
|
|
71
74
|
presentation: {
|
|
72
75
|
buildPendingPayload: ({ request, view }) => {
|
|
73
76
|
const req = request;
|
|
74
|
-
const text = isExecRequest(req) ? buildExecApprovalText(req) : buildPluginApprovalText(req);
|
|
75
|
-
const
|
|
77
|
+
const text = isExecRequest(req) ? buildExecApprovalText(req) : buildPluginApprovalText(req, view.actions);
|
|
78
|
+
const decisionActions = listDecisionActions(view.actions);
|
|
79
|
+
const keyboard = decisionActions.length > 0 ? buildApprovalKeyboard(req.id, decisionActions) : void 0;
|
|
76
80
|
getBridgeLogger().debug?.(`[qqbot:approval-runtime] buildPendingPayload requestId=${req.id} kind=${isExecRequest(req) ? "exec" : "plugin"}`);
|
|
77
81
|
return {
|
|
78
82
|
text,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as normalizeOptionalString, n as normalizeLowercaseStringOrEmpty, s as sanitizeFileName } from "./string-normalize-R_0cKO7Q.js";
|
|
2
|
-
import { a as getQQBotDataDir, f as normalizePath, n as parseTarget$1, p as resolveQQBotPayloadLocalFilePath, s as getQQBotMediaDir, u as isLocalPath } from "./channel-
|
|
2
|
+
import { a as getQQBotDataDir, f as normalizePath, n as parseTarget$1, p as resolveQQBotPayloadLocalFilePath, s as getQQBotMediaDir, u as isLocalPath } from "./channel-C_7BS_5A.js";
|
|
3
3
|
import { A as checkFileSize, C as debugError, E as UploadDailyLimitExceededError, F as getImageMimeType, I as getMaxUploadSize, L as readFileAsync, M as fileExistsAsync, N as formatFileSize, O as UPLOAD_PREPARE_FALLBACK_CODE, P as getFileTypeName, T as debugWarn, i as accountToCreds, j as downloadFile, p as initApiConfig, v as sendMedia$1, w as debugLog, y as sendText$1, z as formatErrorMessage } from "./runtime-TzkQ0YbR.js";
|
|
4
4
|
import { pathExistsSync, resolveLocalPathFromRootsSync } from "openclaw/plugin-sdk/security-runtime";
|
|
5
5
|
import path from "node:path";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getQQBotDataDir, c as getQQBotMediaPath, d as isWindows, i as getHomeDir } from "./channel-
|
|
1
|
+
import { a as getQQBotDataDir, c as getQQBotMediaPath, d as isWindows, i as getHomeDir } from "./channel-C_7BS_5A.js";
|
|
2
2
|
import { w as debugLog } from "./runtime-TzkQ0YbR.js";
|
|
3
3
|
import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import fs from "node:fs";
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.27-beta.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/qqbot",
|
|
9
|
-
"version": "2026.5.
|
|
9
|
+
"version": "2026.5.27-beta.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@tencent-connect/qqbot-connector": "1.1.0",
|
|
12
12
|
"mpg123-decoder": "1.0.3",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"zod": "4.4.3"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"openclaw": ">=2026.5.
|
|
18
|
+
"openclaw": ">=2026.5.27-beta.1"
|
|
19
19
|
},
|
|
20
20
|
"peerDependenciesMeta": {
|
|
21
21
|
"openclaw": {
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.27-beta.1",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "OpenClaw QQ Bot channel plugin",
|
|
5
|
+
"description": "OpenClaw QQ Bot channel plugin for group and direct-message workflows.",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/openclaw/openclaw"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"zod": "4.4.3"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"openclaw": ">=2026.5.
|
|
19
|
+
"openclaw": ">=2026.5.27-beta.1"
|
|
20
20
|
},
|
|
21
21
|
"peerDependenciesMeta": {
|
|
22
22
|
"openclaw": {
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"minHostVersion": ">=2026.4.10"
|
|
46
46
|
},
|
|
47
47
|
"compat": {
|
|
48
|
-
"pluginApi": ">=2026.5.
|
|
48
|
+
"pluginApi": ">=2026.5.27-beta.1"
|
|
49
49
|
},
|
|
50
50
|
"build": {
|
|
51
|
-
"openclawVersion": "2026.5.
|
|
51
|
+
"openclawVersion": "2026.5.27-beta.1"
|
|
52
52
|
},
|
|
53
53
|
"release": {
|
|
54
54
|
"publishToClawHub": true,
|