@openclaw/qqbot 2026.6.6-beta.1 → 2026.6.6

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 CHANGED
@@ -1,4 +1,4 @@
1
- import { t as qqbotPlugin } from "./channel-CQdcwOQZ.js";
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
4
  import { t as getFrameworkCommands } from "./slash-commands-impl-DVApdSop.js";
@@ -377,7 +377,7 @@ function createQQBotApprovalCapability() {
377
377
  },
378
378
  load: async () => {
379
379
  ensurePlatformAdapter();
380
- return (await import("./handler-runtime-CPzQAAn3.js")).qqbotApprovalNativeRuntime;
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-DTfz_8KD.js");
670
+ gatewayModulePromise ??= import("./gateway-fUg0QRoq.js");
671
671
  return gatewayModulePromise;
672
672
  }
673
673
  let outboundMessagingModulePromise;
@@ -1,2 +1,2 @@
1
- import { t as qqbotPlugin } from "./channel-CQdcwOQZ.js";
1
+ import { t as qqbotPlugin } from "./channel-CIb8DUm3.js";
2
2
  export { qqbotPlugin };
@@ -1,7 +1,7 @@
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-CQdcwOQZ.js";
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";
@@ -26,6 +26,7 @@ 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";
@@ -5736,6 +5737,19 @@ function immediateToolProgressText(payload) {
5736
5737
  if (payload.mediaUrl || payload.mediaUrls?.length) return;
5737
5738
  return text;
5738
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
+ }
5739
5753
  /**
5740
5754
  * Dispatch the AI reply for the given inbound context.
5741
5755
  *
@@ -5763,50 +5777,78 @@ async function dispatchOutbound(inbound, deps) {
5763
5777
  const ctxPayload = await buildCtxPayload(inbound, runtime, cfg);
5764
5778
  let hasResponse = false;
5765
5779
  let hasBlockResponse = false;
5780
+ let hasVisibleBlockResponse = false;
5766
5781
  let toolDeliverCount = 0;
5767
5782
  const toolTexts = [];
5768
5783
  const toolMediaUrls = [];
5769
5784
  let toolFallbackSent = false;
5770
5785
  let toolRenewalCount = 0;
5786
+ let skippedSilentBlockResponse = false;
5771
5787
  let timeoutId = null;
5772
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
+ };
5773
5834
  const sendToolFallback = async () => {
5774
5835
  if (toolMediaUrls.length > 0) {
5775
- for (const mediaUrl of toolMediaUrls) {
5776
- const ac = new AbortController();
5777
- try {
5778
- const result = await Promise.race([sendMedia$1({
5779
- to: qualifiedTarget,
5780
- text: "",
5781
- mediaUrl,
5782
- accountId: account.accountId,
5783
- replyToId: event.messageId,
5784
- account
5785
- }).then((r) => {
5786
- if (ac.signal.aborted) return {
5787
- channel: "qqbot",
5788
- error: "suppressed"
5789
- };
5790
- return r;
5791
- }), new Promise((resolve) => {
5792
- setTimeout(() => {
5793
- ac.abort();
5794
- resolve({
5795
- channel: "qqbot",
5796
- error: "timeout"
5797
- });
5798
- }, TOOL_MEDIA_SEND_TIMEOUT);
5799
- })]);
5800
- if (result.error) log?.error(`Tool fallback error: ${result.error}`);
5801
- } catch (err) {
5802
- log?.error(`Tool fallback failed: ${String(err)}`);
5803
- }
5804
- }
5836
+ for (const mediaUrl of toolMediaUrls) await sendToolMediaWithTimeout(mediaUrl, {
5837
+ resultError: "Tool fallback error",
5838
+ thrownError: "Tool fallback failed"
5839
+ });
5805
5840
  return;
5806
5841
  }
5807
5842
  if (toolTexts.length > 0) await sendErrorMessage(toolTexts.slice(-3).join("\n---\n").slice(0, 2e3));
5808
5843
  };
5809
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
+ };
5810
5852
  const renewToolOnlyFallback = () => {
5811
5853
  if (toolFallbackSent) return false;
5812
5854
  if (toolOnlyTimeoutId) {
@@ -5815,7 +5857,7 @@ async function dispatchOutbound(inbound, deps) {
5815
5857
  toolRenewalCount++;
5816
5858
  }
5817
5859
  toolOnlyTimeoutId = setTimeout(() => {
5818
- if (!hasBlockResponse && !toolFallbackSent) {
5860
+ if (!hasBlockResponse && !toolFallbackSent && !skippedSilentBlockResponse) {
5819
5861
  toolFallbackSent = true;
5820
5862
  sendToolFallback().catch(() => {});
5821
5863
  }
@@ -5842,6 +5884,32 @@ async function dispatchOutbound(inbound, deps) {
5842
5884
  textToSpeech: (params) => runtime.tts.textToSpeech(params),
5843
5885
  audioFileToSilkBase64: async (p) => await audioFileToSilkBase64(p) ?? void 0
5844
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
+ };
5845
5913
  const recordOutbound = () => runtime.channel.activity.record({
5846
5914
  channel: "qqbot",
5847
5915
  accountId: account.accountId,
@@ -5945,16 +6013,12 @@ async function dispatchOutbound(inbound, deps) {
5945
6013
  renewToolOnlyFallback();
5946
6014
  return;
5947
6015
  }
5948
- hasBlockResponse = true;
5949
- inbound.typing.keepAlive?.stop();
5950
- if (timeoutId) {
5951
- clearTimeout(timeoutId);
5952
- timeoutId = null;
5953
- }
5954
- if (toolOnlyTimeoutId) {
5955
- clearTimeout(toolOnlyTimeoutId);
5956
- 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;
5957
6020
  }
6021
+ hasVisibleBlockResponse = true;
5958
6022
  if (streamingController && !streamingController.isTerminalPhase) {
5959
6023
  try {
5960
6024
  await streamingController.onDeliver(payload);
@@ -5980,7 +6044,7 @@ async function dispatchOutbound(inbound, deps) {
5980
6044
  return quoteRef;
5981
6045
  }
5982
6046
  };
5983
- let replyText = payload.text ?? "";
6047
+ let replyText = blockReplyTextForDelivery(payload);
5984
6048
  const deliverEvent = {
5985
6049
  type: event.type,
5986
6050
  senderId: event.senderId,
@@ -6027,6 +6091,15 @@ async function dispatchOutbound(inbound, deps) {
6027
6091
  clearTimeout(timeoutId);
6028
6092
  timeoutId = null;
6029
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
+ }
6030
6103
  }
6031
6104
  },
6032
6105
  replyOptions: {
@@ -6050,13 +6123,20 @@ async function dispatchOutbound(inbound, deps) {
6050
6123
  try {
6051
6124
  await Promise.race([dispatchPromise, timeoutPromise]);
6052
6125
  } catch {
6053
- if (timeoutId) clearTimeout(timeoutId);
6126
+ if (timeoutId) {
6127
+ clearTimeout(timeoutId);
6128
+ timeoutId = null;
6129
+ }
6054
6130
  } finally {
6131
+ if (timeoutId) {
6132
+ clearTimeout(timeoutId);
6133
+ timeoutId = null;
6134
+ }
6055
6135
  if (toolOnlyTimeoutId) {
6056
6136
  clearTimeout(toolOnlyTimeoutId);
6057
6137
  toolOnlyTimeoutId = null;
6058
6138
  }
6059
- if (toolDeliverCount > 0 && !hasBlockResponse && !toolFallbackSent) {
6139
+ if (toolDeliverCount > 0 && !hasBlockResponse && !toolFallbackSent && !skippedSilentBlockResponse) {
6060
6140
  toolFallbackSent = true;
6061
6141
  await sendToolFallback();
6062
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-CQdcwOQZ.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-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";
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/qqbot",
3
- "version": "2026.6.6-beta.1",
3
+ "version": "2026.6.6",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/qqbot",
9
- "version": "2026.6.6-beta.1",
9
+ "version": "2026.6.6",
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.6-beta.1"
18
+ "openclaw": ">=2026.6.6"
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.6-beta.1",
3
+ "version": "2026.6.6",
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.6-beta.1"
19
+ "openclaw": ">=2026.6.6"
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.6-beta.1"
48
+ "pluginApi": ">=2026.6.6"
49
49
  },
50
50
  "build": {
51
- "openclawVersion": "2026.6.6-beta.1"
51
+ "openclawVersion": "2026.6.6"
52
52
  },
53
53
  "release": {
54
54
  "publishToClawHub": true,