@openclaw/qqbot 2026.6.5 → 2026.6.6-beta.2
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-D13iTVCr.js → channel-CIb8DUm3.js} +2 -2
- package/dist/{channel-entry-fUBLXKPr.js → channel-entry-CfzBEypJ.js} +1 -1
- package/dist/channel-entry-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{gateway-DcL6jnps.js → gateway-fUg0QRoq.js} +129 -47
- package/dist/{handler-runtime-DZXDF0GH.js → handler-runtime-ChANl8Bb.js} +1 -1
- package/dist/{slash-commands-impl-FRw-Dl44.js → slash-commands-impl-DVApdSop.js} +84 -0
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
package/dist/api.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as qqbotPlugin } from "./channel-
|
|
1
|
+
import { t as qqbotPlugin } from "./channel-CIb8DUm3.js";
|
|
2
2
|
import { a as resolveQQBotAccount, i as resolveDefaultQQBotAccountId, n as applyQQBotAccountConfig, r as listQQBotAccountIds, t as DEFAULT_ACCOUNT_ID } from "./config-ZEfgeoL4.js";
|
|
3
3
|
import { t as qqbotSetupPlugin } from "./channel.setup-CQ_DFfPx.js";
|
|
4
|
-
import { t as getFrameworkCommands } from "./slash-commands-impl-
|
|
4
|
+
import { t as getFrameworkCommands } from "./slash-commands-impl-DVApdSop.js";
|
|
5
5
|
import { n as registerRemindTool, r as registerChannelTool, t as registerQQBotTools } from "./tools-2d9t-N1b.js";
|
|
6
|
-
import { t as registerQQBotFull } from "./channel-entry-
|
|
6
|
+
import { t as registerQQBotFull } from "./channel-entry-CfzBEypJ.js";
|
|
7
7
|
import { C as getMessageReplyStats, D as setOutboundAudioPort, E as OUTBOUND_ERROR_CODES, S as getMessageReplyConfig, T as DEFAULT_MEDIA_SEND_ERROR, _ as sendVideoMsg, a as sendText, b as MESSAGE_REPLY_LIMIT, f as buildMediaTarget, g as sendPhoto, h as sendDocument, i as sendProactiveMessage, m as resolveOutboundMediaPath, n as sendCronMessage, p as parseTarget, r as sendMedia, v as sendVoice, w as recordMessageReply, x as checkMessageReplyLimit, y as resolveUserFacingMediaError } from "./outbound-C9wV892v.js";
|
|
8
8
|
export { DEFAULT_ACCOUNT_ID, DEFAULT_MEDIA_SEND_ERROR, MESSAGE_REPLY_LIMIT, OUTBOUND_ERROR_CODES, applyQQBotAccountConfig, buildMediaTarget, checkMessageReplyLimit, getFrameworkCommands, getMessageReplyConfig, getMessageReplyStats, listQQBotAccountIds, parseTarget, qqbotPlugin, qqbotSetupPlugin, recordMessageReply, registerChannelTool, registerQQBotFull, registerQQBotTools, registerRemindTool, resolveDefaultQQBotAccountId, resolveOutboundMediaPath, resolveQQBotAccount, resolveUserFacingMediaError, sendCronMessage, sendDocument, sendMedia, sendPhoto, sendProactiveMessage, sendText, sendVideoMsg, sendVoice, setOutboundAudioPort };
|
|
@@ -377,7 +377,7 @@ function createQQBotApprovalCapability() {
|
|
|
377
377
|
},
|
|
378
378
|
load: async () => {
|
|
379
379
|
ensurePlatformAdapter();
|
|
380
|
-
return (await import("./handler-runtime-
|
|
380
|
+
return (await import("./handler-runtime-ChANl8Bb.js")).qqbotApprovalNativeRuntime;
|
|
381
381
|
}
|
|
382
382
|
})
|
|
383
383
|
});
|
|
@@ -667,7 +667,7 @@ function resolveQQBotGroupToolPolicy(params) {
|
|
|
667
667
|
//#region extensions/qqbot/src/channel.ts
|
|
668
668
|
let gatewayModulePromise;
|
|
669
669
|
function loadGatewayModule() {
|
|
670
|
-
gatewayModulePromise ??= import("./gateway-
|
|
670
|
+
gatewayModulePromise ??= import("./gateway-fUg0QRoq.js");
|
|
671
671
|
return gatewayModulePromise;
|
|
672
672
|
}
|
|
673
673
|
let outboundMessagingModulePromise;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as resolveQQBotAccount } from "./config-ZEfgeoL4.js";
|
|
2
|
-
import { t as getFrameworkCommands } from "./slash-commands-impl-
|
|
2
|
+
import { t as getFrameworkCommands } from "./slash-commands-impl-DVApdSop.js";
|
|
3
3
|
import { t as registerQQBotTools } from "./tools-2d9t-N1b.js";
|
|
4
4
|
import { h as sendDocument } from "./outbound-C9wV892v.js";
|
|
5
5
|
//#region extensions/qqbot/src/bridge/commands/framework-context-adapter.ts
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as registerQQBotFull } from "./channel-entry-
|
|
1
|
+
import { t as registerQQBotFull } from "./channel-entry-CfzBEypJ.js";
|
|
2
2
|
export { registerQQBotFull };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as qqbotPlugin } from "./channel-
|
|
1
|
+
import { t as qqbotPlugin } from "./channel-CIb8DUm3.js";
|
|
2
2
|
export { qqbotPlugin };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { C as getNextMsgSeq, D as downloadFile, F as StreamInputMode, I as StreamInputState, M as getMaxUploadSize, P as StreamContentType, T as openLocalFile, a as createRawInputNotifyFn, b as stopBackgroundTokenRefresh, c as getMessageApi, d as initSender, f as onMessageSent, g as sendText, h as sendMedia, i as clearTokenCache, j as getImageMimeType, k as formatFileSize, l as getPluginUserAgent, m as sendInputNotify, n as acknowledgeInteraction, o as getAccessToken, p as registerAccount, r as buildDeliveryTarget, s as getGatewayUrl, t as accountToCreds, u as initApiConfig, x as withTokenRetry, y as startBackgroundTokenRefresh } from "./sender-DIMG7jHz.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 { c as setBridgeLogger, o as ensurePlatformAdapter } from "./config-schema-BFLNZ8Nf.js";
|
|
4
|
-
import { a as authorizeQQBotApprovalAction, i as toGatewayAccount, n as buildQQBotStateKey, p as parseApprovalButtonData, r as openQQBotSyncKeyedStore } from "./channel-
|
|
4
|
+
import { a as authorizeQQBotApprovalAction, i as toGatewayAccount, n as buildQQBotStateKey, p as parseApprovalButtonData, r as openQQBotSyncKeyedStore } from "./channel-CIb8DUm3.js";
|
|
5
5
|
import { d as resolveAccountBase } from "./config-ZEfgeoL4.js";
|
|
6
6
|
import { a as formatErrorMessage, i as formatDuration, n as debugLog, r as debugWarn, t as debugError } from "./log-SDfMMBWe.js";
|
|
7
7
|
import { n as getQQBotRuntimeForEngine, t as getQQBotRuntime } from "./runtime-B9UoQ5NI.js";
|
|
8
8
|
import { a as getHomeDir, c as getQQBotMediaDir, d as isLocalPath, f as isWindows, i as checkSilkWasmAvailable, m as resolveQQBotPayloadLocalFilePath, o as getQQBotDataDir, p as normalizePath, s as getQQBotDataPath, u as getTempDir } from "./target-parser-BdCUmxK7.js";
|
|
9
|
-
import { a as matchSlashCommand, i as initCommands, n as getFrameworkVersion, r as getPluginVersion } from "./slash-commands-impl-
|
|
9
|
+
import { a as matchSlashCommand, i as initCommands, n as getFrameworkVersion, r as getPluginVersion } from "./slash-commands-impl-DVApdSop.js";
|
|
10
10
|
import { n as runWithRequestContext } from "./request-context-Bm7PTBD1.js";
|
|
11
11
|
import { D as setOutboundAudioPort, T as DEFAULT_MEDIA_SEND_ERROR, _ as sendVideoMsg, c as isCronReminderPayload, d as normalizeMediaTags, g as sendPhoto, h as sendDocument, l as isMediaPayload, o as decodeMediaPath, r as sendMedia$1, s as encodePayloadForCron, u as parseQQBotPayload, v as sendVoice, y as resolveUserFacingMediaError } from "./outbound-C9wV892v.js";
|
|
12
12
|
import { asBoolean, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
@@ -21,11 +21,12 @@ import * as path$1 from "node:path";
|
|
|
21
21
|
import path from "node:path";
|
|
22
22
|
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
|
23
23
|
import { MAX_TIMER_TIMEOUT_MS, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
24
|
-
import { resolveRuntimeServiceVersion } from "openclaw/plugin-sdk/cli-runtime";
|
|
25
24
|
import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
25
|
+
import { resolveRuntimeServiceVersion } from "openclaw/plugin-sdk/cli-runtime";
|
|
26
26
|
import WebSocket from "ws";
|
|
27
27
|
import { resolveAmbientNodeProxyAgent } from "openclaw/plugin-sdk/extension-shared";
|
|
28
28
|
import { buildChannelInboundEventContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
29
|
+
import { SILENT_REPLY_TOKEN, isSilentReplyPayloadText } from "openclaw/plugin-sdk/reply-chunking";
|
|
29
30
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
30
31
|
import { fileURLToPath } from "node:url";
|
|
31
32
|
import { parseAccessGroupAllowFromEntry } from "openclaw/plugin-sdk/access-groups";
|
|
@@ -2595,11 +2596,13 @@ function readHistoryLimit(obj, key) {
|
|
|
2595
2596
|
return Math.max(0, Math.floor(v));
|
|
2596
2597
|
}
|
|
2597
2598
|
function resolveGroupConfig(cfg, groupOpenid, accountId) {
|
|
2599
|
+
const account = resolveAccountBase(cfg, accountId);
|
|
2598
2600
|
const groups = readGroupsMap(cfg, accountId);
|
|
2599
2601
|
const wildcard = groups["*"] ?? {};
|
|
2600
2602
|
const specific = groupOpenid ? groups[groupOpenid] ?? {} : {};
|
|
2603
|
+
const accountDefaultRequireMention = asBoolean(account.config.defaultRequireMention) ?? DEFAULT_GROUP_CONFIG.requireMention;
|
|
2601
2604
|
return {
|
|
2602
|
-
requireMention: readBoolean(specific, "requireMention") ?? readBoolean(wildcard, "requireMention") ??
|
|
2605
|
+
requireMention: readBoolean(specific, "requireMention") ?? readBoolean(wildcard, "requireMention") ?? accountDefaultRequireMention,
|
|
2603
2606
|
ignoreOtherMentions: readBoolean(specific, "ignoreOtherMentions") ?? readBoolean(wildcard, "ignoreOtherMentions") ?? DEFAULT_GROUP_CONFIG.ignoreOtherMentions,
|
|
2604
2607
|
name: readString(specific, "name") ?? readString(wildcard, "name") ?? DEFAULT_GROUP_CONFIG.name,
|
|
2605
2608
|
prompt: readString(specific, "prompt") ?? readString(wildcard, "prompt"),
|
|
@@ -5734,6 +5737,19 @@ function immediateToolProgressText(payload) {
|
|
|
5734
5737
|
if (payload.mediaUrl || payload.mediaUrls?.length) return;
|
|
5735
5738
|
return text;
|
|
5736
5739
|
}
|
|
5740
|
+
function hasReplyMedia(payload) {
|
|
5741
|
+
return Boolean(payload.mediaUrl || payload.mediaUrls?.length);
|
|
5742
|
+
}
|
|
5743
|
+
function isSilentBlockReplyText(text) {
|
|
5744
|
+
return !text || text === "[SKIP]" || isSilentReplyPayloadText(text, SILENT_REPLY_TOKEN);
|
|
5745
|
+
}
|
|
5746
|
+
function blockReplyTextForDelivery(payload) {
|
|
5747
|
+
const text = payload.text ?? "";
|
|
5748
|
+
return isSilentBlockReplyText(text.trim()) ? "" : text;
|
|
5749
|
+
}
|
|
5750
|
+
function isSilentBlockReply(payload) {
|
|
5751
|
+
return !hasReplyMedia(payload) && isSilentBlockReplyText((payload.text ?? "").trim());
|
|
5752
|
+
}
|
|
5737
5753
|
/**
|
|
5738
5754
|
* Dispatch the AI reply for the given inbound context.
|
|
5739
5755
|
*
|
|
@@ -5761,50 +5777,78 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5761
5777
|
const ctxPayload = await buildCtxPayload(inbound, runtime, cfg);
|
|
5762
5778
|
let hasResponse = false;
|
|
5763
5779
|
let hasBlockResponse = false;
|
|
5780
|
+
let hasVisibleBlockResponse = false;
|
|
5764
5781
|
let toolDeliverCount = 0;
|
|
5765
5782
|
const toolTexts = [];
|
|
5766
5783
|
const toolMediaUrls = [];
|
|
5767
5784
|
let toolFallbackSent = false;
|
|
5768
5785
|
let toolRenewalCount = 0;
|
|
5786
|
+
let skippedSilentBlockResponse = false;
|
|
5769
5787
|
let timeoutId = null;
|
|
5770
5788
|
let toolOnlyTimeoutId = null;
|
|
5789
|
+
const markBlockResponse = () => {
|
|
5790
|
+
hasBlockResponse = true;
|
|
5791
|
+
inbound.typing.keepAlive?.stop();
|
|
5792
|
+
if (timeoutId) {
|
|
5793
|
+
clearTimeout(timeoutId);
|
|
5794
|
+
timeoutId = null;
|
|
5795
|
+
}
|
|
5796
|
+
if (toolOnlyTimeoutId) {
|
|
5797
|
+
clearTimeout(toolOnlyTimeoutId);
|
|
5798
|
+
toolOnlyTimeoutId = null;
|
|
5799
|
+
}
|
|
5800
|
+
};
|
|
5801
|
+
const sendToolMediaWithTimeout = async (mediaUrl, labels) => {
|
|
5802
|
+
const ac = new AbortController();
|
|
5803
|
+
let mediaTimeoutId = null;
|
|
5804
|
+
try {
|
|
5805
|
+
const result = await Promise.race([sendMedia$1({
|
|
5806
|
+
to: qualifiedTarget,
|
|
5807
|
+
text: "",
|
|
5808
|
+
mediaUrl,
|
|
5809
|
+
accountId: account.accountId,
|
|
5810
|
+
replyToId: event.messageId,
|
|
5811
|
+
account
|
|
5812
|
+
}).then((r) => {
|
|
5813
|
+
if (ac.signal.aborted) return {
|
|
5814
|
+
channel: "qqbot",
|
|
5815
|
+
error: "suppressed"
|
|
5816
|
+
};
|
|
5817
|
+
return r;
|
|
5818
|
+
}), new Promise((resolve) => {
|
|
5819
|
+
mediaTimeoutId = setTimeout(() => {
|
|
5820
|
+
ac.abort();
|
|
5821
|
+
resolve({
|
|
5822
|
+
channel: "qqbot",
|
|
5823
|
+
error: "timeout"
|
|
5824
|
+
});
|
|
5825
|
+
}, TOOL_MEDIA_SEND_TIMEOUT);
|
|
5826
|
+
})]);
|
|
5827
|
+
if (result.error) log?.error(`${labels.resultError}: ${result.error}`);
|
|
5828
|
+
} catch (err) {
|
|
5829
|
+
log?.error(`${labels.thrownError}: ${String(err)}`);
|
|
5830
|
+
} finally {
|
|
5831
|
+
if (mediaTimeoutId) clearTimeout(mediaTimeoutId);
|
|
5832
|
+
}
|
|
5833
|
+
};
|
|
5771
5834
|
const sendToolFallback = async () => {
|
|
5772
5835
|
if (toolMediaUrls.length > 0) {
|
|
5773
|
-
for (const mediaUrl of toolMediaUrls) {
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
to: qualifiedTarget,
|
|
5778
|
-
text: "",
|
|
5779
|
-
mediaUrl,
|
|
5780
|
-
accountId: account.accountId,
|
|
5781
|
-
replyToId: event.messageId,
|
|
5782
|
-
account
|
|
5783
|
-
}).then((r) => {
|
|
5784
|
-
if (ac.signal.aborted) return {
|
|
5785
|
-
channel: "qqbot",
|
|
5786
|
-
error: "suppressed"
|
|
5787
|
-
};
|
|
5788
|
-
return r;
|
|
5789
|
-
}), new Promise((resolve) => {
|
|
5790
|
-
setTimeout(() => {
|
|
5791
|
-
ac.abort();
|
|
5792
|
-
resolve({
|
|
5793
|
-
channel: "qqbot",
|
|
5794
|
-
error: "timeout"
|
|
5795
|
-
});
|
|
5796
|
-
}, TOOL_MEDIA_SEND_TIMEOUT);
|
|
5797
|
-
})]);
|
|
5798
|
-
if (result.error) log?.error(`Tool fallback error: ${result.error}`);
|
|
5799
|
-
} catch (err) {
|
|
5800
|
-
log?.error(`Tool fallback failed: ${String(err)}`);
|
|
5801
|
-
}
|
|
5802
|
-
}
|
|
5836
|
+
for (const mediaUrl of toolMediaUrls) await sendToolMediaWithTimeout(mediaUrl, {
|
|
5837
|
+
resultError: "Tool fallback error",
|
|
5838
|
+
thrownError: "Tool fallback failed"
|
|
5839
|
+
});
|
|
5803
5840
|
return;
|
|
5804
5841
|
}
|
|
5805
5842
|
if (toolTexts.length > 0) await sendErrorMessage(toolTexts.slice(-3).join("\n---\n").slice(0, 2e3));
|
|
5806
5843
|
};
|
|
5807
5844
|
const hasPendingToolFallbackPayload = () => toolTexts.length > 0 || toolMediaUrls.length > 0;
|
|
5845
|
+
const flushPendingToolDeliveriesOnce = async () => {
|
|
5846
|
+
if (toolFallbackSent || !hasPendingToolFallbackPayload()) return false;
|
|
5847
|
+
await flushPendingToolDeliveries();
|
|
5848
|
+
toolFallbackSent = true;
|
|
5849
|
+
recordOutbound();
|
|
5850
|
+
return true;
|
|
5851
|
+
};
|
|
5808
5852
|
const renewToolOnlyFallback = () => {
|
|
5809
5853
|
if (toolFallbackSent) return false;
|
|
5810
5854
|
if (toolOnlyTimeoutId) {
|
|
@@ -5813,7 +5857,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5813
5857
|
toolRenewalCount++;
|
|
5814
5858
|
}
|
|
5815
5859
|
toolOnlyTimeoutId = setTimeout(() => {
|
|
5816
|
-
if (!hasBlockResponse && !toolFallbackSent) {
|
|
5860
|
+
if (!hasBlockResponse && !toolFallbackSent && !skippedSilentBlockResponse) {
|
|
5817
5861
|
toolFallbackSent = true;
|
|
5818
5862
|
sendToolFallback().catch(() => {});
|
|
5819
5863
|
}
|
|
@@ -5840,6 +5884,32 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5840
5884
|
textToSpeech: (params) => runtime.tts.textToSpeech(params),
|
|
5841
5885
|
audioFileToSilkBase64: async (p) => await audioFileToSilkBase64(p) ?? void 0
|
|
5842
5886
|
} };
|
|
5887
|
+
const flushPendingToolDeliveries = async () => {
|
|
5888
|
+
if (toolMediaUrls.length > 0) {
|
|
5889
|
+
const urlsToSend = [...toolMediaUrls];
|
|
5890
|
+
toolMediaUrls.length = 0;
|
|
5891
|
+
for (const mediaUrl of urlsToSend) await sendToolMediaWithTimeout(mediaUrl, {
|
|
5892
|
+
resultError: "Tool media forward error",
|
|
5893
|
+
thrownError: "Tool media forward failed"
|
|
5894
|
+
});
|
|
5895
|
+
}
|
|
5896
|
+
if (toolTexts.length > 0) {
|
|
5897
|
+
const textsToSend = [...toolTexts];
|
|
5898
|
+
toolTexts.length = 0;
|
|
5899
|
+
for (const text of textsToSend) await sendTextOnlyReply(text, {
|
|
5900
|
+
type: event.type,
|
|
5901
|
+
senderId: event.senderId,
|
|
5902
|
+
messageId: event.messageId,
|
|
5903
|
+
channelId: event.channelId,
|
|
5904
|
+
groupOpenid: event.groupOpenid,
|
|
5905
|
+
msgIdx: event.msgIdx
|
|
5906
|
+
}, {
|
|
5907
|
+
account,
|
|
5908
|
+
qualifiedTarget,
|
|
5909
|
+
log
|
|
5910
|
+
}, sendWithRetry, () => void 0, deliverDeps);
|
|
5911
|
+
}
|
|
5912
|
+
};
|
|
5843
5913
|
const recordOutbound = () => runtime.channel.activity.record({
|
|
5844
5914
|
channel: "qqbot",
|
|
5845
5915
|
accountId: account.accountId,
|
|
@@ -5943,16 +6013,12 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5943
6013
|
renewToolOnlyFallback();
|
|
5944
6014
|
return;
|
|
5945
6015
|
}
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
timeoutId = null;
|
|
5951
|
-
}
|
|
5952
|
-
if (toolOnlyTimeoutId) {
|
|
5953
|
-
clearTimeout(toolOnlyTimeoutId);
|
|
5954
|
-
toolOnlyTimeoutId = null;
|
|
6016
|
+
markBlockResponse();
|
|
6017
|
+
if (!streamingController && isSilentBlockReply(payload)) {
|
|
6018
|
+
if (!await flushPendingToolDeliveriesOnce() && event.type === "group") log?.info(`Model decided to skip group message (${(payload.text ?? "").trim() || "empty reply"}) from ${event.senderId}`);
|
|
6019
|
+
return;
|
|
5955
6020
|
}
|
|
6021
|
+
hasVisibleBlockResponse = true;
|
|
5956
6022
|
if (streamingController && !streamingController.isTerminalPhase) {
|
|
5957
6023
|
try {
|
|
5958
6024
|
await streamingController.onDeliver(payload);
|
|
@@ -5978,7 +6044,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5978
6044
|
return quoteRef;
|
|
5979
6045
|
}
|
|
5980
6046
|
};
|
|
5981
|
-
let replyText = payload
|
|
6047
|
+
let replyText = blockReplyTextForDelivery(payload);
|
|
5982
6048
|
const deliverEvent = {
|
|
5983
6049
|
type: event.type,
|
|
5984
6050
|
senderId: event.senderId,
|
|
@@ -6025,6 +6091,15 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
6025
6091
|
clearTimeout(timeoutId);
|
|
6026
6092
|
timeoutId = null;
|
|
6027
6093
|
}
|
|
6094
|
+
},
|
|
6095
|
+
onSkip: (_payload, info) => {
|
|
6096
|
+
if (!streamingController && (info.kind === "block" || info.kind === "final") && (info.reason === "silent" || info.reason === "empty")) skippedSilentBlockResponse = true;
|
|
6097
|
+
},
|
|
6098
|
+
onFreshSettledDelivery: async () => {
|
|
6099
|
+
if (skippedSilentBlockResponse && !hasVisibleBlockResponse) {
|
|
6100
|
+
markBlockResponse();
|
|
6101
|
+
if (await flushPendingToolDeliveriesOnce()) return { visibleReplySent: true };
|
|
6102
|
+
}
|
|
6028
6103
|
}
|
|
6029
6104
|
},
|
|
6030
6105
|
replyOptions: {
|
|
@@ -6048,13 +6123,20 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
6048
6123
|
try {
|
|
6049
6124
|
await Promise.race([dispatchPromise, timeoutPromise]);
|
|
6050
6125
|
} catch {
|
|
6051
|
-
if (timeoutId)
|
|
6126
|
+
if (timeoutId) {
|
|
6127
|
+
clearTimeout(timeoutId);
|
|
6128
|
+
timeoutId = null;
|
|
6129
|
+
}
|
|
6052
6130
|
} finally {
|
|
6131
|
+
if (timeoutId) {
|
|
6132
|
+
clearTimeout(timeoutId);
|
|
6133
|
+
timeoutId = null;
|
|
6134
|
+
}
|
|
6053
6135
|
if (toolOnlyTimeoutId) {
|
|
6054
6136
|
clearTimeout(toolOnlyTimeoutId);
|
|
6055
6137
|
toolOnlyTimeoutId = null;
|
|
6056
6138
|
}
|
|
6057
|
-
if (toolDeliverCount > 0 && !hasBlockResponse && !toolFallbackSent) {
|
|
6139
|
+
if (toolDeliverCount > 0 && !hasBlockResponse && !toolFallbackSent && !skippedSilentBlockResponse) {
|
|
6058
6140
|
toolFallbackSent = true;
|
|
6059
6141
|
await sendToolFallback();
|
|
6060
6142
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as getMessageApi, t as accountToCreds } from "./sender-DIMG7jHz.js";
|
|
2
2
|
import { o as ensurePlatformAdapter, s as getBridgeLogger } from "./config-schema-BFLNZ8Nf.js";
|
|
3
|
-
import { c as resolveQQBotExecApprovalConfig, d as buildExecApprovalText, f as buildPluginApprovalText, l as shouldHandleQQBotExecApprovalRequest, m as resolveApprovalTarget, o as isQQBotExecApprovalClientEnabled, s as matchesQQBotApprovalAccount, u as buildApprovalKeyboard } from "./channel-
|
|
3
|
+
import { c as resolveQQBotExecApprovalConfig, d as buildExecApprovalText, f as buildPluginApprovalText, l as shouldHandleQQBotExecApprovalRequest, m as resolveApprovalTarget, o as isQQBotExecApprovalClientEnabled, s as matchesQQBotApprovalAccount, u as buildApprovalKeyboard } from "./channel-CIb8DUm3.js";
|
|
4
4
|
import { a as resolveQQBotAccount } from "./config-ZEfgeoL4.js";
|
|
5
5
|
import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
|
|
6
6
|
import { createChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
@@ -4,6 +4,7 @@ import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { loadJsonFile } from "openclaw/plugin-sdk/json-store";
|
|
7
|
+
import { clearRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
7
8
|
//#region extensions/qqbot/src/engine/commands/builtin/state.ts
|
|
8
9
|
let resolveVersionGetter = () => "unknown";
|
|
9
10
|
let approveRuntimeGetter = null;
|
|
@@ -418,6 +419,88 @@ function registerClearStorageCommands(registry) {
|
|
|
418
419
|
});
|
|
419
420
|
}
|
|
420
421
|
//#endregion
|
|
422
|
+
//#region extensions/qqbot/src/engine/commands/builtin/register-group-allways.ts
|
|
423
|
+
function registerGroupAllwaysCommand(registry) {
|
|
424
|
+
registry.register({
|
|
425
|
+
name: "bot-group-allways",
|
|
426
|
+
description: "修改群消息默认响应模式",
|
|
427
|
+
requireAuth: true,
|
|
428
|
+
c2cOnly: true,
|
|
429
|
+
usage: [
|
|
430
|
+
`/bot-group-allways on AI 自主判断何时发言(无需 @)`,
|
|
431
|
+
`/bot-group-allways off 仅在被 @ 时回复`,
|
|
432
|
+
`/bot-group-allways 查看当前设置`,
|
|
433
|
+
``,
|
|
434
|
+
`设为 on 后,AI 会自主判断每条消息是否需要回复(无需 @)。`,
|
|
435
|
+
`仍可通过 groups.{groupId}.requireMention 对单个群覆盖。`,
|
|
436
|
+
``,
|
|
437
|
+
`优先级:具体群配置 > 通配符 "*" > defaultRequireMention(本指令)> 默认 true`
|
|
438
|
+
].join("\n"),
|
|
439
|
+
handler: async (ctx) => {
|
|
440
|
+
const arg = ctx.args.trim().toLowerCase();
|
|
441
|
+
const currentRequireMention = ctx.accountConfig?.defaultRequireMention ?? true;
|
|
442
|
+
if (!arg) return [
|
|
443
|
+
`🤖 群自主发言状态:${currentRequireMention ? "❌ 仅被 @ 时回复" : "✅ 自主判断何时发言"}`,
|
|
444
|
+
`使用 <qqbot-cmd-input text="/bot-group-allways on" show="/bot-group-allways on"/> 设为自主发言`,
|
|
445
|
+
`使用 <qqbot-cmd-input text="/bot-group-allways off" show="/bot-group-allways off"/> 设为仅被 @ 时回复`
|
|
446
|
+
].join("\n");
|
|
447
|
+
if (arg !== "on" && arg !== "off") return `❌ 参数错误,请使用 on 或 off\n\n示例:/bot-group-allways on`;
|
|
448
|
+
const newRequireMention = arg === "off";
|
|
449
|
+
if (newRequireMention === currentRequireMention) return `🤖 群自主发言已经是"${arg}"状态,无需操作`;
|
|
450
|
+
let runtime;
|
|
451
|
+
try {
|
|
452
|
+
const getter = getApproveRuntimeGetter();
|
|
453
|
+
if (!getter) throw new Error("runtime not available");
|
|
454
|
+
runtime = getter();
|
|
455
|
+
} catch {
|
|
456
|
+
const fwVer = resolveRuntimeServiceVersion();
|
|
457
|
+
const ver = getPluginVersionString();
|
|
458
|
+
return [
|
|
459
|
+
`❌ 当前版本不支持该指令`,
|
|
460
|
+
``,
|
|
461
|
+
`🦞框架版本:${fwVer}`,
|
|
462
|
+
`🤖QQBot 插件版本:v${ver}`,
|
|
463
|
+
``,
|
|
464
|
+
`可通过以下命令手动设置:`,
|
|
465
|
+
``,
|
|
466
|
+
`\`\`\`shell`,
|
|
467
|
+
`# 设为 AI 自主判断何时发言(defaultRequireMention=false)`,
|
|
468
|
+
`openclaw config set channels.qqbot.defaultRequireMention false`,
|
|
469
|
+
`# 或设为仅被 @ 时回复(defaultRequireMention=true)`,
|
|
470
|
+
`openclaw config set channels.qqbot.defaultRequireMention true`,
|
|
471
|
+
`\`\`\``
|
|
472
|
+
].join("\n");
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
const configApi = runtime.config;
|
|
476
|
+
const currentCfg = structuredClone(configApi.current());
|
|
477
|
+
const qqbot = (currentCfg.channels ?? {}).qqbot;
|
|
478
|
+
if (!qqbot) return `❌ 配置文件中未找到 qqbot 通道配置`;
|
|
479
|
+
const accountId = ctx.accountId;
|
|
480
|
+
if (accountId !== "default" && Boolean(qqbot.accounts?.[accountId])) {
|
|
481
|
+
const nextAccounts = { ...qqbot.accounts ?? {} };
|
|
482
|
+
const acct = { ...nextAccounts[accountId] };
|
|
483
|
+
acct.defaultRequireMention = newRequireMention;
|
|
484
|
+
nextAccounts[accountId] = acct;
|
|
485
|
+
qqbot.accounts = nextAccounts;
|
|
486
|
+
} else qqbot.defaultRequireMention = newRequireMention;
|
|
487
|
+
await configApi.replaceConfigFile({
|
|
488
|
+
nextConfig: currentCfg,
|
|
489
|
+
afterWrite: { mode: "auto" }
|
|
490
|
+
});
|
|
491
|
+
clearRuntimeConfigSnapshot();
|
|
492
|
+
return [
|
|
493
|
+
`✅ 群自主发言已设置为 ${newRequireMention ? "**off**(仅被 @ 时回复)" : "**on**(AI 自主判断何时发言)"}`,
|
|
494
|
+
``,
|
|
495
|
+
newRequireMention ? `仅在被 @ 机器人才会回复。` : `AI 将自主判断群消息是否需要回复,无需被 @ 即可发言。`
|
|
496
|
+
].join("\n");
|
|
497
|
+
} catch (err) {
|
|
498
|
+
return `❌ 配置写入失败: ${err instanceof Error ? err.message : String(err)}`;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
//#endregion
|
|
421
504
|
//#region extensions/qqbot/src/engine/commands/builtin/log-helpers.ts
|
|
422
505
|
/** Read user-configured log file paths from local config files. */
|
|
423
506
|
function getConfiguredLogFiles() {
|
|
@@ -790,6 +873,7 @@ function registerBuiltinSlashCommands(registry) {
|
|
|
790
873
|
registerClearStorageCommands(registry);
|
|
791
874
|
registerStreamingCommands(registry);
|
|
792
875
|
registerApproveCommands(registry);
|
|
876
|
+
registerGroupAllwaysCommand(registry);
|
|
793
877
|
}
|
|
794
878
|
//#endregion
|
|
795
879
|
//#region extensions/qqbot/src/engine/commands/slash-commands.ts
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.6-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/qqbot",
|
|
9
|
-
"version": "2026.6.
|
|
9
|
+
"version": "2026.6.6-beta.2",
|
|
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.6.
|
|
18
|
+
"openclaw": ">=2026.6.6-beta.2"
|
|
19
19
|
},
|
|
20
20
|
"peerDependenciesMeta": {
|
|
21
21
|
"openclaw": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.6-beta.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OpenClaw QQ Bot channel plugin for group and direct-message workflows.",
|
|
6
6
|
"repository": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"zod": "4.4.3"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"openclaw": ">=2026.6.
|
|
19
|
+
"openclaw": ">=2026.6.6-beta.2"
|
|
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.6.
|
|
48
|
+
"pluginApi": ">=2026.6.6-beta.2"
|
|
49
49
|
},
|
|
50
50
|
"build": {
|
|
51
|
-
"openclawVersion": "2026.6.
|
|
51
|
+
"openclawVersion": "2026.6.6-beta.2"
|
|
52
52
|
},
|
|
53
53
|
"release": {
|
|
54
54
|
"publishToClawHub": true,
|