@openclaw/qqbot 2026.5.28 → 2026.5.31-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 +14 -9
- package/dist/{channel-8Efx0wKu.js → channel-DsUMS0Az.js} +12 -7
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-BxGpVkdx.js → channel.setup-_OAH-xmU.js} +1 -1
- package/dist/{config-schema-iX2iJzKm.js → config-schema-Bc-ArbIT.js} +7 -2
- package/dist/{gateway-CuTCxSqs.js → gateway-Bx-wZKqQ.js} +88 -30
- package/dist/{handler-runtime-C-5nL3Cl.js → handler-runtime-TwO5-5cH.js} +3 -3
- package/dist/{outbound-Ba5ryGDm.js → outbound-CgW0-dMd.js} +19 -6
- package/dist/{request-context-BCsRtyph.js → request-context-DNbuU0Co.js} +2 -2
- package/dist/{runtime-DWfbz21q.js → runtime-DDu_1bny.js} +28 -16
- package/dist/runtime-api.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
package/dist/api.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
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-
|
|
2
|
-
import { c as listQQBotAccountIds, l as resolveDefaultQQBotAccountId, o as DEFAULT_ACCOUNT_ID, s as applyQQBotAccountConfig, u as resolveQQBotAccount } from "./config-schema-
|
|
3
|
-
import { t as qqbotPlugin } from "./channel-
|
|
4
|
-
import { C as debugError, l as getAccessToken, w as debugLog, z as formatErrorMessage } from "./runtime-
|
|
5
|
-
import { t as qqbotSetupPlugin } from "./channel.setup-
|
|
6
|
-
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-
|
|
1
|
+
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-CgW0-dMd.js";
|
|
2
|
+
import { c as listQQBotAccountIds, l as resolveDefaultQQBotAccountId, o as DEFAULT_ACCOUNT_ID, s as applyQQBotAccountConfig, u as resolveQQBotAccount } from "./config-schema-Bc-ArbIT.js";
|
|
3
|
+
import { t as qqbotPlugin } from "./channel-DsUMS0Az.js";
|
|
4
|
+
import { C as debugError, l as getAccessToken, w as debugLog, z as formatErrorMessage } from "./runtime-DDu_1bny.js";
|
|
5
|
+
import { t as qqbotSetupPlugin } from "./channel.setup-_OAH-xmU.js";
|
|
6
|
+
import { r as getFrameworkCommands, t as getRequestContext } from "./request-context-DNbuU0Co.js";
|
|
7
|
+
import { resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
7
8
|
import { callGatewayTool } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
8
9
|
//#region extensions/qqbot/src/engine/tools/channel-api.ts
|
|
9
10
|
/**
|
|
@@ -320,8 +321,7 @@ function buildReminderPrompt(content) {
|
|
|
320
321
|
return `You are a warm reminder assistant. Please remind the user about: ${content}. Requirements: (1) do not reply with HEARTBEAT_OK (2) do not explain who you are (3) output a direct and caring reminder message (4) you may add a short encouraging line (5) keep it within 2-3 sentences (6) use a small amount of emoji.`;
|
|
321
322
|
}
|
|
322
323
|
/** Build cron job params for a one-shot delayed reminder. */
|
|
323
|
-
function buildOnceJob(params,
|
|
324
|
-
const atMs = Date.now() + delayMs;
|
|
324
|
+
function buildOnceJob(params, atMs, to, accountId) {
|
|
325
325
|
const content = params.content;
|
|
326
326
|
return {
|
|
327
327
|
action: "add",
|
|
@@ -448,10 +448,15 @@ function prepareRemindCronAction(params, ctx = {}) {
|
|
|
448
448
|
ok: false,
|
|
449
449
|
error: "Reminder delay must be at least 30 seconds"
|
|
450
450
|
};
|
|
451
|
+
const atMs = resolveExpiresAtMsFromDurationMs(delayMs);
|
|
452
|
+
if (atMs === void 0) return {
|
|
453
|
+
ok: false,
|
|
454
|
+
error: "Reminder time is outside the supported Date range"
|
|
455
|
+
};
|
|
451
456
|
return {
|
|
452
457
|
ok: true,
|
|
453
458
|
action: "add",
|
|
454
|
-
cronAction: buildOnceJob(params,
|
|
459
|
+
cronAction: buildOnceJob(params, atMs, resolvedTo, resolvedAccountId),
|
|
455
460
|
summary: `⏰ Reminder in ${formatDelay(delayMs)}: "${params.content}"`
|
|
456
461
|
};
|
|
457
462
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as getPlatformAdapter, t as asOptionalObjectRecord } from "./string-normalize-R_0cKO7Q.js";
|
|
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-
|
|
3
|
-
import { T as debugWarn, t as getQQBotRuntime, w as debugLog, z as formatErrorMessage } from "./runtime-
|
|
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-Bc-ArbIT.js";
|
|
3
|
+
import { T as debugWarn, t as getQQBotRuntime, w as debugLog, z as formatErrorMessage } from "./runtime-DDu_1bny.js";
|
|
4
4
|
import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/approval-runtime";
|
|
5
5
|
import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
|
|
6
6
|
import { createChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
|
|
@@ -374,7 +374,7 @@ function createQQBotApprovalCapability() {
|
|
|
374
374
|
},
|
|
375
375
|
load: async () => {
|
|
376
376
|
ensurePlatformAdapter();
|
|
377
|
-
return (await import("./handler-runtime-
|
|
377
|
+
return (await import("./handler-runtime-TwO5-5cH.js")).qqbotApprovalNativeRuntime;
|
|
378
378
|
}
|
|
379
379
|
})
|
|
380
380
|
});
|
|
@@ -813,7 +813,7 @@ function clearAccountCredentials(cfg, accountId) {
|
|
|
813
813
|
* @throws {Error} When the target format is invalid.
|
|
814
814
|
*/
|
|
815
815
|
function parseTarget(to) {
|
|
816
|
-
|
|
816
|
+
const id = to.replace(/^qqbot:/i, "");
|
|
817
817
|
if (id.startsWith("c2c:")) {
|
|
818
818
|
const userId = id.slice(4);
|
|
819
819
|
if (!userId) throw new Error(`Invalid c2c target format: ${to} - missing user ID`);
|
|
@@ -868,9 +868,14 @@ function looksLikeQQBotTarget(id) {
|
|
|
868
868
|
//#region extensions/qqbot/src/channel.ts
|
|
869
869
|
let gatewayModulePromise;
|
|
870
870
|
function loadGatewayModule() {
|
|
871
|
-
gatewayModulePromise ??= import("./gateway-
|
|
871
|
+
gatewayModulePromise ??= import("./gateway-Bx-wZKqQ.js");
|
|
872
872
|
return gatewayModulePromise;
|
|
873
873
|
}
|
|
874
|
+
let outboundMessagingModulePromise;
|
|
875
|
+
function loadOutboundMessagingModule() {
|
|
876
|
+
outboundMessagingModulePromise ??= import("./outbound-CgW0-dMd.js").then((n) => n.t);
|
|
877
|
+
return outboundMessagingModulePromise;
|
|
878
|
+
}
|
|
874
879
|
function createQQBotSendReceipt(params) {
|
|
875
880
|
const messageId = params.messageId?.trim();
|
|
876
881
|
return createMessageReceiptFromOutboundResults({
|
|
@@ -886,7 +891,7 @@ function createQQBotSendReceipt(params) {
|
|
|
886
891
|
async function sendQQBotText(params) {
|
|
887
892
|
await loadGatewayModule();
|
|
888
893
|
const account = resolveQQBotAccount(params.cfg, params.accountId);
|
|
889
|
-
const { sendText } = await
|
|
894
|
+
const { sendText } = await loadOutboundMessagingModule();
|
|
890
895
|
const result = await sendText({
|
|
891
896
|
to: params.to,
|
|
892
897
|
text: params.text,
|
|
@@ -908,7 +913,7 @@ async function sendQQBotText(params) {
|
|
|
908
913
|
async function sendQQBotMedia(params) {
|
|
909
914
|
await loadGatewayModule();
|
|
910
915
|
const account = resolveQQBotAccount(params.cfg, params.accountId);
|
|
911
|
-
const { sendMedia } = await
|
|
916
|
+
const { sendMedia } = await loadOutboundMessagingModule();
|
|
912
917
|
const result = await sendMedia({
|
|
913
918
|
to: params.to,
|
|
914
919
|
text: params.text ?? "",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as qqbotPlugin } from "./channel-
|
|
1
|
+
import { t as qqbotPlugin } from "./channel-DsUMS0Az.js";
|
|
2
2
|
export { qqbotPlugin };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-
|
|
1
|
+
import { a as qqbotSetupAdapterShared, i as qqbotMeta, n as qqbotSetupWizard, r as qqbotConfigAdapter, t as qqbotChannelConfigSchema } from "./config-schema-Bc-ArbIT.js";
|
|
2
2
|
//#region extensions/qqbot/src/channel.setup.ts
|
|
3
3
|
/**
|
|
4
4
|
* Setup-only QQBot plugin — lightweight subset used during `openclaw onboard`
|
|
@@ -48,6 +48,11 @@ function getBridgeLogger() {
|
|
|
48
48
|
* statically at the top level so they work reliably in both production and
|
|
49
49
|
* vitest (which resolves bare specifiers via `resolve.alias`, not Node CJS).
|
|
50
50
|
*/
|
|
51
|
+
let mediaRuntimeModulePromise = null;
|
|
52
|
+
const loadMediaRuntimeModule = async () => {
|
|
53
|
+
mediaRuntimeModulePromise ??= import("openclaw/plugin-sdk/media-runtime");
|
|
54
|
+
return await mediaRuntimeModulePromise;
|
|
55
|
+
};
|
|
51
56
|
function createBuiltinAdapter() {
|
|
52
57
|
return {
|
|
53
58
|
async validateRemoteUrl(_url, _options) {},
|
|
@@ -55,7 +60,7 @@ function createBuiltinAdapter() {
|
|
|
55
60
|
if (typeof value === "string") return value || void 0;
|
|
56
61
|
},
|
|
57
62
|
async downloadFile(url, destDir, filename) {
|
|
58
|
-
const { readRemoteMediaBuffer } = await
|
|
63
|
+
const { readRemoteMediaBuffer } = await loadMediaRuntimeModule();
|
|
59
64
|
const result = await readRemoteMediaBuffer({
|
|
60
65
|
url,
|
|
61
66
|
filePathHint: filename
|
|
@@ -68,7 +73,7 @@ function createBuiltinAdapter() {
|
|
|
68
73
|
return destPath;
|
|
69
74
|
},
|
|
70
75
|
async fetchMedia(options) {
|
|
71
|
-
const { readRemoteMediaBuffer } = await
|
|
76
|
+
const { readRemoteMediaBuffer } = await loadMediaRuntimeModule();
|
|
72
77
|
const result = await readRemoteMediaBuffer({
|
|
73
78
|
url: options.url,
|
|
74
79
|
filePathHint: options.filePathHint,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
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, s as encodePayloadForCron, u as parseQQBotPayload, v as sendVoice, y as resolveUserFacingMediaError } from "./outbound-
|
|
1
|
+
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, s as encodePayloadForCron, u as parseQQBotPayload, v as sendVoice, y as resolveUserFacingMediaError } from "./outbound-CgW0-dMd.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
|
-
import { f as resolveAccountBase, h as setBridgeLogger, p as ensurePlatformAdapter } from "./config-schema-
|
|
4
|
-
import { C as parseApprovalButtonData, a as getQQBotDataDir, d as isWindows, f as normalizePath, 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-
|
|
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-
|
|
6
|
-
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-
|
|
3
|
+
import { f as resolveAccountBase, h as setBridgeLogger, p as ensurePlatformAdapter } from "./config-schema-Bc-ArbIT.js";
|
|
4
|
+
import { C as parseApprovalButtonData, a as getQQBotDataDir, d as isWindows, f as normalizePath, 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-DsUMS0Az.js";
|
|
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-DDu_1bny.js";
|
|
6
|
+
import { a as getPluginVersion, i as getFrameworkVersion, n as runWithRequestContext, o as initCommands, s as matchSlashCommand } from "./request-context-DNbuU0Co.js";
|
|
7
7
|
import { asBoolean, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
8
|
import { isImplicitSameChatApprovalAuthorization } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
9
9
|
import * as fs$1 from "node:fs";
|
|
@@ -84,7 +84,7 @@ const TRANSCRIPT_SOURCE_LABELS = {
|
|
|
84
84
|
* Shared grammar (both modes):
|
|
85
85
|
*
|
|
86
86
|
* ```
|
|
87
|
-
* attachment_with_source := "
|
|
87
|
+
* attachment_with_source := "[" TYPE_LABEL ": " SOURCE "]" [voice_suffix]
|
|
88
88
|
* voice_suffix := ' (transcript: "' TEXT '")' [source_suffix]
|
|
89
89
|
* attachment_no_source := "[" TYPE_LABEL [": " FILENAME] [voice_suffix_bare] "]" [source_suffix_bare]
|
|
90
90
|
* voice_suffix_bare := ' (transcript: "' TEXT '")'
|
|
@@ -116,7 +116,7 @@ function formatAttachmentTags(attachments) {
|
|
|
116
116
|
* Render a single attachment.
|
|
117
117
|
*
|
|
118
118
|
* The function is split into two orthogonal concerns:
|
|
119
|
-
* - `renderBody`: the shared "
|
|
119
|
+
* - `renderBody`: the shared "[type: source]…" or "[type…]" string.
|
|
120
120
|
* - `renderSourceSuffix`: ref-mode-only `" [source: …]"` tail.
|
|
121
121
|
*
|
|
122
122
|
* Both consumers produce the same body; only the suffix differs.
|
|
@@ -128,8 +128,9 @@ function renderOne(att, mode) {
|
|
|
128
128
|
function renderBody(att) {
|
|
129
129
|
const source = att.localPath || att.url;
|
|
130
130
|
const voiceSuffix = att.type === "voice" && att.transcript ? ` (transcript: "${att.transcript}")` : "";
|
|
131
|
-
|
|
132
|
-
return `[${
|
|
131
|
+
const label = labelForType(att.type);
|
|
132
|
+
if (source) return `[${label}: ${source}]${voiceSuffix}`;
|
|
133
|
+
return `[${label}${att.filename ? `: ${att.filename}` : ""}${voiceSuffix}]`;
|
|
133
134
|
}
|
|
134
135
|
/**
|
|
135
136
|
* Ref-mode-only tail that records where a voice transcript came from.
|
|
@@ -234,7 +235,7 @@ function appendLine(line) {
|
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
237
|
function shouldCompact() {
|
|
237
|
-
return
|
|
238
|
+
return cache !== null && totalLinesOnDisk > cache.size * COMPACT_THRESHOLD_RATIO && totalLinesOnDisk > 1e3;
|
|
238
239
|
}
|
|
239
240
|
function compactFile() {
|
|
240
241
|
if (!cache) return;
|
|
@@ -1976,7 +1977,8 @@ async function processAttachments(attachments, ctx) {
|
|
|
1976
1977
|
attachmentLocalPaths
|
|
1977
1978
|
};
|
|
1978
1979
|
}
|
|
1979
|
-
async function processVoiceAttachment(localPath,
|
|
1980
|
+
async function processVoiceAttachment(localPath, audioPathInput, att, asrReferText, cfg, downloadDir, audioConvert, log) {
|
|
1981
|
+
let audioPath = audioPathInput;
|
|
1980
1982
|
const wavUrl = att.voice_wav_url ? att.voice_wav_url.startsWith("//") ? `https:${att.voice_wav_url}` : att.voice_wav_url : "";
|
|
1981
1983
|
const attUrl = att.url?.startsWith("//") ? `https:${att.url}` : att.url;
|
|
1982
1984
|
const meta = {
|
|
@@ -3498,13 +3500,14 @@ async function autoMediaBatch(params) {
|
|
|
3498
3500
|
}
|
|
3499
3501
|
}
|
|
3500
3502
|
async function sendTextChunkToTarget(params) {
|
|
3501
|
-
const { account, event, text, consumeQuoteRef, allowDm } = params;
|
|
3503
|
+
const { account, event, text, consumeQuoteRef, allowDm, forcePlainText } = params;
|
|
3502
3504
|
const ref = consumeQuoteRef();
|
|
3503
3505
|
const target = buildDeliveryTarget(event);
|
|
3504
3506
|
if (target.type === "dm" && !allowDm) return;
|
|
3505
3507
|
return await sendText(target, text, accountToCreds(account), {
|
|
3506
3508
|
msgId: event.messageId,
|
|
3507
|
-
messageReference: ref
|
|
3509
|
+
messageReference: ref,
|
|
3510
|
+
forcePlainText
|
|
3508
3511
|
});
|
|
3509
3512
|
}
|
|
3510
3513
|
async function sendTextChunks(text, event, actx, sendWithRetry, consumeQuoteRef, deps) {
|
|
@@ -3521,8 +3524,25 @@ async function sendTextChunks(text, event, actx, sendWithRetry, consumeQuoteRef,
|
|
|
3521
3524
|
onError: (err) => `Failed to send text chunk: ${formatErrorMessage(err)}`
|
|
3522
3525
|
});
|
|
3523
3526
|
}
|
|
3527
|
+
async function sendTextOnlyReply(text, event, actx, sendWithRetry, consumeQuoteRef, deps) {
|
|
3528
|
+
const safeText = filterInternalMarkers(text).trim();
|
|
3529
|
+
if (!safeText) return;
|
|
3530
|
+
const { account, log } = actx;
|
|
3531
|
+
await sendTextChunksWithRetry({
|
|
3532
|
+
account,
|
|
3533
|
+
event,
|
|
3534
|
+
chunks: deps.chunkText(safeText, TEXT_CHUNK_LIMIT),
|
|
3535
|
+
sendWithRetry,
|
|
3536
|
+
consumeQuoteRef,
|
|
3537
|
+
allowDm: true,
|
|
3538
|
+
forcePlainText: true,
|
|
3539
|
+
log,
|
|
3540
|
+
onSuccess: (chunk) => `Sent text-only chunk (${chunk.length}/${safeText.length} chars): ${chunk.slice(0, 50)}...`,
|
|
3541
|
+
onError: (err) => `Failed to send text-only chunk: ${formatErrorMessage(err)}`
|
|
3542
|
+
});
|
|
3543
|
+
}
|
|
3524
3544
|
async function sendTextChunksWithRetry(params) {
|
|
3525
|
-
const { account, event, chunks, sendWithRetry, consumeQuoteRef, allowDm, log } = params;
|
|
3545
|
+
const { account, event, chunks, sendWithRetry, consumeQuoteRef, allowDm, forcePlainText, log } = params;
|
|
3526
3546
|
for (const chunk of chunks) try {
|
|
3527
3547
|
await sendWithRetry((token) => sendTextChunkToTarget({
|
|
3528
3548
|
account,
|
|
@@ -3530,7 +3550,8 @@ async function sendTextChunksWithRetry(params) {
|
|
|
3530
3550
|
token,
|
|
3531
3551
|
text: chunk,
|
|
3532
3552
|
consumeQuoteRef,
|
|
3533
|
-
allowDm
|
|
3553
|
+
allowDm,
|
|
3554
|
+
forcePlainText
|
|
3534
3555
|
}));
|
|
3535
3556
|
log?.info(params.onSuccess(chunk));
|
|
3536
3557
|
} catch (err) {
|
|
@@ -4242,7 +4263,7 @@ function fixPathEncoding(mediaPath, log) {
|
|
|
4242
4263
|
const hasNonASCII = /[\u0080-\u00FF]/.test(result);
|
|
4243
4264
|
if (!isWinLocal && (hasOctal || hasNonASCII)) {
|
|
4244
4265
|
log?.debug?.(`Decoding path with mixed encoding: ${result}`);
|
|
4245
|
-
|
|
4266
|
+
const decoded = result.replace(/\\([0-7]{1,3})/g, (_, octal) => String.fromCharCode(Number.parseInt(octal, 8)));
|
|
4246
4267
|
const bytes = [];
|
|
4247
4268
|
for (let i = 0; i < decoded.length; i++) {
|
|
4248
4269
|
const code = decoded.charCodeAt(i);
|
|
@@ -4310,7 +4331,6 @@ function findFirstClosedMediaTag(text, log) {
|
|
|
4310
4331
|
const textBefore = text.slice(0, match.index);
|
|
4311
4332
|
const tagName = match[1].toLowerCase();
|
|
4312
4333
|
let mediaPath = match[2]?.trim() ?? "";
|
|
4313
|
-
if (mediaPath.startsWith("MEDIA:")) mediaPath = mediaPath.slice(6);
|
|
4314
4334
|
mediaPath = normalizePath(mediaPath);
|
|
4315
4335
|
mediaPath = fixPathEncoding(mediaPath, log);
|
|
4316
4336
|
return {
|
|
@@ -5671,6 +5691,18 @@ function resolveResponseTimeoutMs(cfg) {
|
|
|
5671
5691
|
const TOOL_ONLY_TIMEOUT = 6e4;
|
|
5672
5692
|
const MAX_TOOL_RENEWALS = 3;
|
|
5673
5693
|
const TOOL_MEDIA_SEND_TIMEOUT = 45e3;
|
|
5694
|
+
function shouldDeliverToolProgressImmediately(account, useOfficialC2cStream) {
|
|
5695
|
+
if (useOfficialC2cStream) return true;
|
|
5696
|
+
const streaming = account.config?.streaming;
|
|
5697
|
+
if (streaming === true) return true;
|
|
5698
|
+
return typeof streaming === "object" && streaming !== null && streaming.mode !== "off";
|
|
5699
|
+
}
|
|
5700
|
+
function immediateToolProgressText(payload) {
|
|
5701
|
+
const text = (payload.text ?? "").trim();
|
|
5702
|
+
if (!text || payload.isError || payload.audioAsVoice) return;
|
|
5703
|
+
if (payload.mediaUrl || payload.mediaUrls?.length) return;
|
|
5704
|
+
return text;
|
|
5705
|
+
}
|
|
5674
5706
|
/**
|
|
5675
5707
|
* Dispatch the AI reply for the given inbound context.
|
|
5676
5708
|
*
|
|
@@ -5739,6 +5771,24 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5739
5771
|
}
|
|
5740
5772
|
if (toolTexts.length > 0) await sendErrorMessage(toolTexts.slice(-3).join("\n---\n").slice(0, 2e3));
|
|
5741
5773
|
};
|
|
5774
|
+
const hasPendingToolFallbackPayload = () => toolTexts.length > 0 || toolMediaUrls.length > 0;
|
|
5775
|
+
const renewToolOnlyFallback = () => {
|
|
5776
|
+
if (toolFallbackSent) return false;
|
|
5777
|
+
if (toolOnlyTimeoutId) {
|
|
5778
|
+
if (toolRenewalCount >= MAX_TOOL_RENEWALS) return false;
|
|
5779
|
+
clearTimeout(toolOnlyTimeoutId);
|
|
5780
|
+
toolRenewalCount++;
|
|
5781
|
+
}
|
|
5782
|
+
toolOnlyTimeoutId = setTimeout(async () => {
|
|
5783
|
+
if (!hasBlockResponse && !toolFallbackSent) {
|
|
5784
|
+
toolFallbackSent = true;
|
|
5785
|
+
try {
|
|
5786
|
+
await sendToolFallback();
|
|
5787
|
+
} catch {}
|
|
5788
|
+
}
|
|
5789
|
+
}, TOOL_ONLY_TIMEOUT);
|
|
5790
|
+
return true;
|
|
5791
|
+
};
|
|
5742
5792
|
const responseTimeoutMs = resolveResponseTimeoutMs(cfg);
|
|
5743
5793
|
const timeoutPromise = new Promise((_, reject) => {
|
|
5744
5794
|
timeoutId = setTimeout(() => {
|
|
@@ -5766,6 +5816,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5766
5816
|
});
|
|
5767
5817
|
const messagesConfig = runtime.channel.reply.resolveEffectiveMessagesConfig(cfg, inbound.route.agentId);
|
|
5768
5818
|
const useOfficialC2cStream = shouldUseOfficialC2cStream(account, event.type === "c2c" ? "c2c" : event.type === "group" ? "group" : "channel");
|
|
5819
|
+
const deliverToolProgressImmediately = shouldDeliverToolProgressImmediately(account, useOfficialC2cStream);
|
|
5769
5820
|
let streamingController = null;
|
|
5770
5821
|
if (useOfficialC2cStream) streamingController = new StreamingController({
|
|
5771
5822
|
account,
|
|
@@ -5821,6 +5872,24 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5821
5872
|
if (info.kind === "tool") {
|
|
5822
5873
|
toolDeliverCount++;
|
|
5823
5874
|
const toolText = (payload.text ?? "").trim();
|
|
5875
|
+
const textOnlyProgress = immediateToolProgressText(payload);
|
|
5876
|
+
if (!hasBlockResponse && deliverToolProgressImmediately && textOnlyProgress) {
|
|
5877
|
+
if (toolOnlyTimeoutId || hasPendingToolFallbackPayload()) renewToolOnlyFallback();
|
|
5878
|
+
await sendTextOnlyReply(textOnlyProgress, {
|
|
5879
|
+
type: event.type,
|
|
5880
|
+
senderId: event.senderId,
|
|
5881
|
+
messageId: event.messageId,
|
|
5882
|
+
channelId: event.channelId,
|
|
5883
|
+
groupOpenid: event.groupOpenid,
|
|
5884
|
+
msgIdx: event.msgIdx
|
|
5885
|
+
}, {
|
|
5886
|
+
account,
|
|
5887
|
+
qualifiedTarget,
|
|
5888
|
+
log
|
|
5889
|
+
}, sendWithRetry, () => void 0, deliverDeps);
|
|
5890
|
+
recordOutbound();
|
|
5891
|
+
return;
|
|
5892
|
+
}
|
|
5824
5893
|
if (toolText) toolTexts.push(toolText);
|
|
5825
5894
|
if (payload.mediaUrls?.length) toolMediaUrls.push(...payload.mediaUrls);
|
|
5826
5895
|
if (payload.mediaUrl && !toolMediaUrls.includes(payload.mediaUrl)) toolMediaUrls.push(payload.mediaUrl);
|
|
@@ -5840,18 +5909,7 @@ async function dispatchOutbound(inbound, deps) {
|
|
|
5840
5909
|
return;
|
|
5841
5910
|
}
|
|
5842
5911
|
if (toolFallbackSent) return;
|
|
5843
|
-
|
|
5844
|
-
clearTimeout(toolOnlyTimeoutId);
|
|
5845
|
-
toolRenewalCount++;
|
|
5846
|
-
} else return;
|
|
5847
|
-
toolOnlyTimeoutId = setTimeout(async () => {
|
|
5848
|
-
if (!hasBlockResponse && !toolFallbackSent) {
|
|
5849
|
-
toolFallbackSent = true;
|
|
5850
|
-
try {
|
|
5851
|
-
await sendToolFallback();
|
|
5852
|
-
} catch {}
|
|
5853
|
-
}
|
|
5854
|
-
}, TOOL_ONLY_TIMEOUT);
|
|
5912
|
+
renewToolOnlyFallback();
|
|
5855
5913
|
return;
|
|
5856
5914
|
}
|
|
5857
5915
|
hasBlockResponse = true;
|
|
@@ -6567,7 +6625,7 @@ async function startGateway(ctx) {
|
|
|
6567
6625
|
context: { account: ctx.account },
|
|
6568
6626
|
abortSignal: ctx.abortSignal
|
|
6569
6627
|
});
|
|
6570
|
-
accountLogger.info(`approval.native context registered (lease=${
|
|
6628
|
+
accountLogger.info(`approval.native context registered (lease=${Boolean(lease)})`);
|
|
6571
6629
|
} else accountLogger.info("No channelRuntime — skipping approval.native registration");
|
|
6572
6630
|
return startGateway$1({
|
|
6573
6631
|
account: toGatewayAccount(ctx.account),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { m as getBridgeLogger, p as ensurePlatformAdapter, u as resolveQQBotAccount } from "./config-schema-
|
|
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-
|
|
3
|
-
import { d as getMessageApi, i as accountToCreds } from "./runtime-
|
|
1
|
+
import { m as getBridgeLogger, p as ensurePlatformAdapter, u as resolveQQBotAccount } from "./config-schema-Bc-ArbIT.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-DsUMS0Az.js";
|
|
3
|
+
import { d as getMessageApi, i as accountToCreds } from "./runtime-DDu_1bny.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
|
|
@@ -1,6 +1,6 @@
|
|
|
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$1, n as parseTarget$1, p as resolveQQBotPayloadLocalFilePath, s as getQQBotMediaDir, u as isLocalPath } from "./channel-
|
|
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-
|
|
2
|
+
import { a as getQQBotDataDir, f as normalizePath$1, n as parseTarget$1, p as resolveQQBotPayloadLocalFilePath, s as getQQBotMediaDir, u as isLocalPath } from "./channel-DsUMS0Az.js";
|
|
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-DDu_1bny.js";
|
|
4
4
|
import { pathExistsSync, resolveLocalPathFromRootsSync } from "openclaw/plugin-sdk/security-runtime";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { getFileExtension } from "openclaw/plugin-sdk/media-mime";
|
|
@@ -997,8 +997,8 @@ function normalizePath(p) {
|
|
|
997
997
|
return result;
|
|
998
998
|
}
|
|
999
999
|
/**
|
|
1000
|
-
* Decode a media path by
|
|
1001
|
-
*
|
|
1000
|
+
* Decode a media path by expanding `~` and unescaping octal/UTF-8 byte
|
|
1001
|
+
* sequences.
|
|
1002
1002
|
*
|
|
1003
1003
|
* @param raw - Raw path string from a media tag.
|
|
1004
1004
|
* @param log - Optional logger for decode diagnostics.
|
|
@@ -1006,7 +1006,6 @@ function normalizePath(p) {
|
|
|
1006
1006
|
*/
|
|
1007
1007
|
function decodeMediaPath(raw, log) {
|
|
1008
1008
|
let mediaPath = raw;
|
|
1009
|
-
if (mediaPath.startsWith("MEDIA:")) mediaPath = mediaPath.slice(6);
|
|
1010
1009
|
mediaPath = normalizePath(mediaPath);
|
|
1011
1010
|
mediaPath = mediaPath.replace(/\\\\/g, "\\");
|
|
1012
1011
|
const isWinLocal = /^[a-zA-Z]:[\\/]/.test(mediaPath) || mediaPath.startsWith("\\\\");
|
|
@@ -1078,10 +1077,24 @@ function isVideoFile$1(filePath, mimeType) {
|
|
|
1078
1077
|
var outbound_exports = /* @__PURE__ */ __exportAll({
|
|
1079
1078
|
DEFAULT_MEDIA_SEND_ERROR: () => DEFAULT_MEDIA_SEND_ERROR,
|
|
1080
1079
|
MESSAGE_REPLY_LIMIT: () => 4,
|
|
1080
|
+
OUTBOUND_ERROR_CODES: () => OUTBOUND_ERROR_CODES,
|
|
1081
|
+
buildMediaTarget: () => buildMediaTarget,
|
|
1082
|
+
checkMessageReplyLimit: () => checkMessageReplyLimit,
|
|
1083
|
+
getMessageReplyConfig: () => getMessageReplyConfig,
|
|
1084
|
+
getMessageReplyStats: () => getMessageReplyStats,
|
|
1085
|
+
parseTarget: () => parseTarget,
|
|
1086
|
+
recordMessageReply: () => recordMessageReply,
|
|
1087
|
+
resolveOutboundMediaPath: () => resolveOutboundMediaPath,
|
|
1088
|
+
resolveUserFacingMediaError: () => resolveUserFacingMediaError,
|
|
1081
1089
|
sendCronMessage: () => sendCronMessage,
|
|
1090
|
+
sendDocument: () => sendDocument,
|
|
1082
1091
|
sendMedia: () => sendMedia,
|
|
1092
|
+
sendPhoto: () => sendPhoto,
|
|
1083
1093
|
sendProactiveMessage: () => sendProactiveMessage,
|
|
1084
|
-
sendText: () => sendText
|
|
1094
|
+
sendText: () => sendText,
|
|
1095
|
+
sendVideoMsg: () => sendVideoMsg,
|
|
1096
|
+
sendVoice: () => sendVoice,
|
|
1097
|
+
setOutboundAudioPort: () => setOutboundAudioPort
|
|
1085
1098
|
});
|
|
1086
1099
|
const isImageFile = isImageFile$1;
|
|
1087
1100
|
const isVideoFile = isVideoFile$1;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as getQQBotDataDir, c as getQQBotMediaPath, d as isWindows, i as getHomeDir } from "./channel-
|
|
2
|
-
import { w as debugLog } from "./runtime-
|
|
1
|
+
import { a as getQQBotDataDir, c as getQQBotMediaPath, d as isWindows, i as getHomeDir } from "./channel-DsUMS0Az.js";
|
|
2
|
+
import { w as debugLog } from "./runtime-DDu_1bny.js";
|
|
3
3
|
import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
@@ -9,7 +9,7 @@ import { FsSafeError, openLocalFileSafely, readRegularFile, statRegularFileSync
|
|
|
9
9
|
import * as path$1 from "node:path";
|
|
10
10
|
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
|
11
11
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
12
|
-
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
12
|
+
import { asDateTimestampMs, isFutureDateTimestampMs, parseStrictPositiveInteger, resolveExpiresAtMsFromDurationSeconds, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
13
13
|
//#region extensions/qqbot/src/engine/types.ts
|
|
14
14
|
/**
|
|
15
15
|
* Core API layer public types.
|
|
@@ -1173,13 +1173,18 @@ var TokenManager = class {
|
|
|
1173
1173
|
throw new Error("QQBot access_token response was malformed JSON");
|
|
1174
1174
|
}
|
|
1175
1175
|
if (!data.access_token) throw new Error(`Failed to get access_token: ${JSON.stringify(data)}`);
|
|
1176
|
-
const
|
|
1176
|
+
const nowMs = asDateTimestampMs(Date.now());
|
|
1177
|
+
if (nowMs === void 0) {
|
|
1178
|
+
this.logger?.debug?.(`[qqbot:token:${appId}] Not cached: invalid process clock`);
|
|
1179
|
+
return data.access_token;
|
|
1180
|
+
}
|
|
1181
|
+
const expiresAt = resolveExpiresAtMsFromDurationSeconds(resolveTokenExpiresInSeconds(data.expires_in), { nowMs }) ?? nowMs;
|
|
1177
1182
|
this.cache.set(appId, {
|
|
1178
1183
|
token: data.access_token,
|
|
1179
1184
|
expiresAt,
|
|
1180
1185
|
appId
|
|
1181
1186
|
});
|
|
1182
|
-
this.logger?.debug?.(`[qqbot:token:${appId}] Cached, expires at: ${
|
|
1187
|
+
this.logger?.debug?.(`[qqbot:token:${appId}] Cached, expires at: ${resolveTimestampMsToIsoString(expiresAt)}`);
|
|
1183
1188
|
return data.access_token;
|
|
1184
1189
|
} finally {
|
|
1185
1190
|
await release?.();
|
|
@@ -1426,15 +1431,15 @@ var MessageApi = class {
|
|
|
1426
1431
|
async sendMessage(scope, targetId, content, creds, opts) {
|
|
1427
1432
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
1428
1433
|
const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;
|
|
1429
|
-
const body = this.buildMessageBody(content, opts?.msgId, msgSeq, opts?.messageReference, opts?.inlineKeyboard);
|
|
1434
|
+
const body = this.buildMessageBody(content, opts?.msgId, msgSeq, opts?.messageReference, opts?.inlineKeyboard, opts?.forcePlainText);
|
|
1430
1435
|
const path = messagePath(scope, targetId);
|
|
1431
1436
|
return this.sendAndNotify(creds.appId, token, "POST", path, body, { text: content });
|
|
1432
1437
|
}
|
|
1433
1438
|
/** Send a proactive (no msgId) message to a C2C or Group target. */
|
|
1434
|
-
async sendProactiveMessage(scope, targetId, content, creds) {
|
|
1439
|
+
async sendProactiveMessage(scope, targetId, content, creds, opts) {
|
|
1435
1440
|
if (!content?.trim()) throw new Error("Proactive message content must not be empty");
|
|
1436
1441
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
1437
|
-
const body = this.buildProactiveBody(content);
|
|
1442
|
+
const body = this.buildProactiveBody(content, opts?.forcePlainText);
|
|
1438
1443
|
const path = messagePath(scope, targetId);
|
|
1439
1444
|
return this.sendAndNotify(creds.appId, token, "POST", path, body, { text: content });
|
|
1440
1445
|
}
|
|
@@ -1508,8 +1513,9 @@ var MessageApi = class {
|
|
|
1508
1513
|
}
|
|
1509
1514
|
return result;
|
|
1510
1515
|
}
|
|
1511
|
-
buildMessageBody(content, msgId, msgSeq, messageReference, inlineKeyboard) {
|
|
1512
|
-
const
|
|
1516
|
+
buildMessageBody(content, msgId, msgSeq, messageReference, inlineKeyboard, forcePlainText = false) {
|
|
1517
|
+
const useMarkdown = this.markdownSupport && !forcePlainText;
|
|
1518
|
+
const body = useMarkdown ? {
|
|
1513
1519
|
markdown: { content },
|
|
1514
1520
|
msg_type: 2,
|
|
1515
1521
|
msg_seq: msgSeq
|
|
@@ -1519,12 +1525,12 @@ var MessageApi = class {
|
|
|
1519
1525
|
msg_seq: msgSeq
|
|
1520
1526
|
};
|
|
1521
1527
|
if (msgId) body.msg_id = msgId;
|
|
1522
|
-
if (messageReference && !
|
|
1528
|
+
if (messageReference && !useMarkdown) body.message_reference = { message_id: messageReference };
|
|
1523
1529
|
if (inlineKeyboard) body.keyboard = inlineKeyboard;
|
|
1524
1530
|
return body;
|
|
1525
1531
|
}
|
|
1526
|
-
buildProactiveBody(content) {
|
|
1527
|
-
return this.markdownSupport ? {
|
|
1532
|
+
buildProactiveBody(content, forcePlainText = false) {
|
|
1533
|
+
return this.markdownSupport && !forcePlainText ? {
|
|
1528
1534
|
markdown: { content },
|
|
1529
1535
|
msg_type: 2
|
|
1530
1536
|
} : {
|
|
@@ -1607,7 +1613,7 @@ function getCachedFileInfo(contentHash, scope, targetId, fileType) {
|
|
|
1607
1613
|
const key = buildCacheKey(contentHash, scope, targetId, fileType);
|
|
1608
1614
|
const entry = cache.get(key);
|
|
1609
1615
|
if (!entry) return null;
|
|
1610
|
-
if (
|
|
1616
|
+
if (!isFutureDateTimestampMs(entry.expiresAt)) {
|
|
1611
1617
|
cache.delete(key);
|
|
1612
1618
|
return null;
|
|
1613
1619
|
}
|
|
@@ -1618,7 +1624,7 @@ function getCachedFileInfo(contentHash, scope, targetId, fileType) {
|
|
|
1618
1624
|
function setCachedFileInfo(contentHash, scope, targetId, fileType, fileInfo, fileUuid, ttl) {
|
|
1619
1625
|
if (cache.size >= MAX_CACHE_SIZE) {
|
|
1620
1626
|
const now = Date.now();
|
|
1621
|
-
for (const [k, v] of cache) if (
|
|
1627
|
+
for (const [k, v] of cache) if (!isFutureDateTimestampMs(v.expiresAt, { nowMs: now })) cache.delete(k);
|
|
1622
1628
|
if (cache.size >= MAX_CACHE_SIZE) {
|
|
1623
1629
|
const keys = Array.from(cache.keys());
|
|
1624
1630
|
for (let i = 0; i < keys.length / 2; i++) cache.delete(keys[i]);
|
|
@@ -1626,10 +1632,15 @@ function setCachedFileInfo(contentHash, scope, targetId, fileType, fileInfo, fil
|
|
|
1626
1632
|
}
|
|
1627
1633
|
const key = buildCacheKey(contentHash, scope, targetId, fileType);
|
|
1628
1634
|
const effectiveTtl = Math.max(ttl - 60, 10);
|
|
1635
|
+
const expiresAt = resolveExpiresAtMsFromDurationSeconds(effectiveTtl);
|
|
1636
|
+
if (expiresAt === void 0) {
|
|
1637
|
+
cache.delete(key);
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1629
1640
|
cache.set(key, {
|
|
1630
1641
|
fileInfo,
|
|
1631
1642
|
fileUuid,
|
|
1632
|
-
expiresAt
|
|
1643
|
+
expiresAt
|
|
1633
1644
|
});
|
|
1634
1645
|
debugLog(`[upload-cache] Cache SET: key=${key.slice(0, 40)}..., ttl=${effectiveTtl}s, uuid=${fileUuid}`);
|
|
1635
1646
|
}
|
|
@@ -1860,9 +1871,10 @@ async function sendText(target, content, creds, opts) {
|
|
|
1860
1871
|
const scope = target.type;
|
|
1861
1872
|
if (opts?.msgId) return api.sendMessage(scope, target.id, content, c, {
|
|
1862
1873
|
msgId: opts.msgId,
|
|
1863
|
-
messageReference: opts.messageReference
|
|
1874
|
+
messageReference: opts.messageReference,
|
|
1875
|
+
forcePlainText: opts.forcePlainText
|
|
1864
1876
|
});
|
|
1865
|
-
return api.sendProactiveMessage(scope, target.id, content, c);
|
|
1877
|
+
return api.sendProactiveMessage(scope, target.id, content, c, { forcePlainText: opts?.forcePlainText });
|
|
1866
1878
|
}
|
|
1867
1879
|
if (target.type === "dm") return api.sendDmMessage({
|
|
1868
1880
|
guildId: target.id,
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as setQQBotRuntime, t as getQQBotRuntime } from "./runtime-
|
|
1
|
+
import { r as setQQBotRuntime, t as getQQBotRuntime } from "./runtime-DDu_1bny.js";
|
|
2
2
|
export { getQQBotRuntime, setQQBotRuntime };
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as qqbotSetupPlugin } from "./channel.setup-
|
|
1
|
+
import { t as qqbotSetupPlugin } from "./channel.setup-_OAH-xmU.js";
|
|
2
2
|
export { qqbotSetupPlugin };
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.31-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.31-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.31-beta.1"
|
|
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.5.
|
|
3
|
+
"version": "2026.5.31-beta.1",
|
|
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.5.
|
|
19
|
+
"openclaw": ">=2026.5.31-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.31-beta.1"
|
|
49
49
|
},
|
|
50
50
|
"build": {
|
|
51
|
-
"openclawVersion": "2026.5.
|
|
51
|
+
"openclawVersion": "2026.5.31-beta.1"
|
|
52
52
|
},
|
|
53
53
|
"release": {
|
|
54
54
|
"publishToClawHub": true,
|