@openclaw/qqbot 2026.7.1-beta.1 → 2026.7.1-beta.4
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 +6 -6
- package/dist/{channel-Bh0MrYvU.js → channel-D1UztsnG.js} +84 -34
- package/dist/{channel-entry-LMtNY-J6.js → channel-entry-C5YdhX3Y.js} +3 -3
- package/dist/channel-entry-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-CldhUlTO.js → channel.setup-2ItDYKhz.js} +1 -1
- package/dist/{config-schema-gMW9zKvQ.js → config-schema-JZEf1dvB.js} +2 -5
- package/dist/{gateway-BgfQAYxB.js → gateway-pJQppxe4.js} +344 -138
- package/dist/{group-DQQsZ6Y0.js → group-o0GmovSf.js} +14 -11
- package/dist/{handler-runtime-BQ72YPsH.js → handler-runtime-zQvT6SrI.js} +3 -3
- package/dist/{log-SDfMMBWe.js → log-DEtcoDWe.js} +3 -4
- package/dist/{outbound-Dfa2uOEp.js → outbound-BIrfvvFJ.js} +310 -68
- package/dist/{runtime-BL0xZzWe.js → runtime-DodcT_fQ.js} +1 -1
- package/dist/runtime-api.js +1 -1
- package/dist/{sender-BHWpE_yH.js → sender-CjDuU-uz.js} +31 -25
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{tools-BvXe7bTq.js → tools-UJJ-tLHP.js} +19 -36
- package/dist/tools-api.js +1 -1
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
- package/skills/qqbot-media/SKILL.md +14 -11
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { v as setOpenClawVersion } from "./sender-
|
|
1
|
+
import { v as setOpenClawVersion } from "./sender-CjDuU-uz.js";
|
|
2
2
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
3
3
|
//#region extensions/qqbot/src/bridge/runtime.ts
|
|
4
4
|
const { setRuntime: _setRuntime, clearRuntime: resetQQBotRuntimeForTest, getRuntime: getQQBotRuntime } = createPluginRuntimeStore({
|
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-DodcT_fQ.js";
|
|
2
2
|
export { getQQBotRuntime, setQQBotRuntime };
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { c as getPlatformAdapter, i as normalizeOptionalString, s as sanitizeFileName } from "./string-normalize-R_0cKO7Q.js";
|
|
2
|
-
import { a as formatErrorMessage, n as debugLog, r as debugWarn, t as debugError } from "./log-
|
|
2
|
+
import { a as formatErrorMessage, n as debugLog, r as debugWarn, t as debugError } from "./log-DEtcoDWe.js";
|
|
3
|
+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
3
4
|
import * as fs$1 from "node:fs";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import { readProviderTextResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
6
7
|
import { fetchWithSsrFGuard, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
7
8
|
import * as crypto$1 from "node:crypto";
|
|
8
9
|
import crypto from "node:crypto";
|
|
10
|
+
import { sleep } from "openclaw/plugin-sdk/runtime-env";
|
|
9
11
|
import { FsSafeError, openLocalFileSafely, readRegularFile, statRegularFileSync } from "openclaw/plugin-sdk/security-runtime";
|
|
10
12
|
import * as path$1 from "node:path";
|
|
11
13
|
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
|
14
|
+
import { asDateTimestampMs, formatByteSize, isFutureDateTimestampMs, parseStrictPositiveInteger, resolveExpiresAtMsFromDurationSeconds, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
12
15
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
13
|
-
import { asDateTimestampMs, isFutureDateTimestampMs, parseStrictPositiveInteger, resolveExpiresAtMsFromDurationSeconds, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
14
16
|
//#region \0rolldown/runtime.js
|
|
15
17
|
var __defProp = Object.defineProperty;
|
|
16
18
|
var __exportAll = (all, no_symbols) => {
|
|
@@ -175,7 +177,7 @@ var ApiClient = class {
|
|
|
175
177
|
throw new ApiError(`API Error [${path}]: ${error.message ?? rawBody}`, res.status, path, bizCode, error.message);
|
|
176
178
|
} catch (parseErr) {
|
|
177
179
|
if (parseErr instanceof ApiError) throw parseErr;
|
|
178
|
-
throw new ApiError(`API Error [${path}] HTTP ${res.status}: ${rawBody
|
|
180
|
+
throw new ApiError(`API Error [${path}] HTTP ${res.status}: ${truncateUtf16Safe(rawBody, 200)}`, res.status, path);
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
if (isHtmlResponse) throw new ApiError(`QQ 服务端返回了非 JSON 响应(${path}),可能是临时故障,请稍后重试`, res.status, path);
|
|
@@ -286,16 +288,19 @@ async function fileExistsAsync(filePath) {
|
|
|
286
288
|
}
|
|
287
289
|
/** Format a byte count into a human-readable size string. */
|
|
288
290
|
function formatFileSize(bytes) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
291
|
+
return formatByteSize(bytes, {
|
|
292
|
+
style: "legacy-binary",
|
|
293
|
+
maxUnit: "mega",
|
|
294
|
+
separator: "",
|
|
295
|
+
fractionDigits: (_value, unit) => unit === "byte" ? null : 1
|
|
296
|
+
});
|
|
292
297
|
}
|
|
293
298
|
/** Infer a MIME type from the file extension. */
|
|
294
299
|
function getMimeType(filePath) {
|
|
295
300
|
return mimeTypeFromFilePath(filePath) ?? "application/octet-stream";
|
|
296
301
|
}
|
|
297
302
|
/** Extensions accepted as image uploads by the QQ Bot media pipeline. */
|
|
298
|
-
const IMAGE_EXTENSIONS = new Set([
|
|
303
|
+
const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
299
304
|
".jpg",
|
|
300
305
|
".jpeg",
|
|
301
306
|
".png",
|
|
@@ -462,6 +467,17 @@ async function normalizeSource(raw, opts = {}) {
|
|
|
462
467
|
//#endregion
|
|
463
468
|
//#region extensions/qqbot/src/engine/api/retry.ts
|
|
464
469
|
/**
|
|
470
|
+
* Generic retry engine for QQ Bot API requests.
|
|
471
|
+
*
|
|
472
|
+
* Replaces the three separate retry implementations in the old `api.ts`:
|
|
473
|
+
* - `apiRequestWithRetry` (upload retry with exponential backoff)
|
|
474
|
+
* - `partFinishWithRetry` (part-finish retry + persistent retry on specific biz codes)
|
|
475
|
+
* - `completeUploadWithRetry` (unconditional retry for complete-upload)
|
|
476
|
+
*
|
|
477
|
+
* All three patterns are expressed as a single `withRetry` function
|
|
478
|
+
* parameterized by `RetryPolicy` and optional `PersistentRetryPolicy`.
|
|
479
|
+
*/
|
|
480
|
+
/**
|
|
465
481
|
* Execute an async operation with configurable retry semantics.
|
|
466
482
|
*
|
|
467
483
|
* @param fn - The async operation to retry.
|
|
@@ -483,8 +499,8 @@ async function withRetry(fn, policy, persistentPolicy, logger) {
|
|
|
483
499
|
if (policy.shouldRetry?.(lastError, attempt) === false) throw lastError;
|
|
484
500
|
if (attempt < policy.maxRetries) {
|
|
485
501
|
const delay = policy.backoff === "exponential" ? policy.baseDelayMs * 2 ** attempt : policy.baseDelayMs;
|
|
486
|
-
logger?.debug?.(`[qqbot:retry] Attempt ${attempt + 1} failed, retrying in ${delay}ms: ${lastError.message
|
|
487
|
-
await sleep
|
|
502
|
+
logger?.debug?.(`[qqbot:retry] Attempt ${attempt + 1} failed, retrying in ${delay}ms: ${truncateUtf16Safe(lastError.message, 100)}`);
|
|
503
|
+
await sleep(delay);
|
|
488
504
|
}
|
|
489
505
|
}
|
|
490
506
|
throw lastError;
|
|
@@ -514,16 +530,11 @@ async function persistentRetryLoop(fn, policy, logger) {
|
|
|
514
530
|
if (remaining <= 0) break;
|
|
515
531
|
const actualDelay = Math.min(policy.intervalMs, remaining);
|
|
516
532
|
(logger?.warn ?? logger?.error)?.(`[qqbot:retry] Persistent retry #${attempt}: retrying in ${actualDelay}ms (remaining=${Math.round(remaining / 1e3)}s)`);
|
|
517
|
-
await sleep
|
|
533
|
+
await sleep(actualDelay);
|
|
518
534
|
}
|
|
519
535
|
logger?.error?.(`[qqbot:retry] Persistent retry timed out after ${policy.timeoutMs / 1e3}s (${attempt} attempts)`);
|
|
520
536
|
throw lastError ?? /* @__PURE__ */ new Error(`Persistent retry timed out (${policy.timeoutMs / 1e3}s)`);
|
|
521
537
|
}
|
|
522
|
-
function sleep$1(ms) {
|
|
523
|
-
return new Promise((resolve) => {
|
|
524
|
-
setTimeout(resolve, ms);
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
538
|
/** Standard upload retry: exponential backoff, skip 400/401/timeout errors. */
|
|
528
539
|
const UPLOAD_RETRY_POLICY = {
|
|
529
540
|
maxRetries: 2,
|
|
@@ -564,7 +575,7 @@ function buildPartFinishPersistentPolicy(retryTimeoutMs, retryableCodes = PART_F
|
|
|
564
575
|
};
|
|
565
576
|
}
|
|
566
577
|
/** Business error codes that trigger persistent part-finish retry. */
|
|
567
|
-
const PART_FINISH_RETRYABLE_CODES = new Set([40093001]);
|
|
578
|
+
const PART_FINISH_RETRYABLE_CODES = /* @__PURE__ */ new Set([40093001]);
|
|
568
579
|
/** upload_prepare error code indicating daily limit exceeded. */
|
|
569
580
|
const UPLOAD_PREPARE_FALLBACK_CODE = 40093002;
|
|
570
581
|
//#endregion
|
|
@@ -931,8 +942,8 @@ async function putToPresignedUrl(presignedUrl, data, partIndex, totalParts, logg
|
|
|
931
942
|
const etag = response.headers.get("ETag") ?? "-";
|
|
932
943
|
if (!response.ok) {
|
|
933
944
|
const body = await readResponseTextLimited(response, PART_UPLOAD_ERROR_BODY_LIMIT_BYTES).catch(() => "");
|
|
934
|
-
logger?.error?.(`${prefix} PUT part ${partIndex}/${totalParts}: HTTP ${response.status} ${response.statusText} (${elapsed}ms, requestId=${requestId}) body=${body
|
|
935
|
-
throw new Error(`COS PUT failed: ${response.status} ${response.statusText} - ${body
|
|
945
|
+
logger?.error?.(`${prefix} PUT part ${partIndex}/${totalParts}: HTTP ${response.status} ${response.statusText} (${elapsed}ms, requestId=${requestId}) body=${truncateUtf16Safe(body, 160)}`);
|
|
946
|
+
throw new Error(`COS PUT failed: ${response.status} ${response.statusText} - ${truncateUtf16Safe(body, 120)}`);
|
|
936
947
|
}
|
|
937
948
|
logger?.debug?.(`${prefix} PUT part ${partIndex}/${totalParts} OK (${elapsed}ms ETag=${etag} requestId=${requestId})`);
|
|
938
949
|
return;
|
|
@@ -944,7 +955,7 @@ async function putToPresignedUrl(presignedUrl, data, partIndex, totalParts, logg
|
|
|
944
955
|
if (lastError.name === "AbortError") lastError = /* @__PURE__ */ new Error(`Part ${partIndex}/${totalParts} upload timeout after ${PART_UPLOAD_TIMEOUT_MS}ms`);
|
|
945
956
|
if (attempt < PART_UPLOAD_MAX_RETRIES) {
|
|
946
957
|
const delay = 1e3 * 2 ** attempt;
|
|
947
|
-
(logger?.warn ?? logger?.error)?.(`${prefix} PUT part ${partIndex}/${totalParts} attempt ${attempt + 1} failed (${lastError.message
|
|
958
|
+
(logger?.warn ?? logger?.error)?.(`${prefix} PUT part ${partIndex}/${totalParts} attempt ${attempt + 1} failed (${truncateUtf16Safe(lastError.message, 120)}), retrying in ${delay}ms`);
|
|
948
959
|
await sleep(delay);
|
|
949
960
|
}
|
|
950
961
|
} finally {
|
|
@@ -967,11 +978,6 @@ async function runWithConcurrency(tasks, maxConcurrent) {
|
|
|
967
978
|
await Promise.all(batch.map((task) => task()));
|
|
968
979
|
}
|
|
969
980
|
}
|
|
970
|
-
function sleep(ms) {
|
|
971
|
-
return new Promise((resolve) => {
|
|
972
|
-
setTimeout(resolve, ms);
|
|
973
|
-
});
|
|
974
|
-
}
|
|
975
981
|
//#endregion
|
|
976
982
|
//#region extensions/qqbot/src/engine/api/token.ts
|
|
977
983
|
/**
|
|
@@ -1810,7 +1816,7 @@ async function withTokenRetry(creds, sendFn, log, _accountId) {
|
|
|
1810
1816
|
}
|
|
1811
1817
|
const errMsg = formatErrorMessage(err);
|
|
1812
1818
|
if (errMsg.includes("401") || errMsg.includes("token") || errMsg.includes("access_token")) {
|
|
1813
|
-
log?.warn?.(`Token retry triggered by string heuristic (err is not ApiError). Consider propagating ApiError end-to-end. msg=${errMsg
|
|
1819
|
+
log?.warn?.(`Token retry triggered by string heuristic (err is not ApiError). Consider propagating ApiError end-to-end. msg=${truncateUtf16Safe(errMsg, 120)}`);
|
|
1814
1820
|
clearTokenCache(creds.appId);
|
|
1815
1821
|
return await sendFn(await getAccessToken(creds.appId, creds.clientSecret));
|
|
1816
1822
|
}
|
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-2ItDYKhz.js";
|
|
2
2
|
export { qqbotSetupPlugin };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { a as resolveQQBotAccount, r as listQQBotAccountIds } from "./config-C1qZbh0K.js";
|
|
2
|
-
import { a as formatErrorMessage, n as debugLog, t as debugError } from "./log-
|
|
2
|
+
import { a as formatErrorMessage, n as debugLog, t as debugError } from "./log-DEtcoDWe.js";
|
|
3
3
|
import { t as getRequestContext } from "./request-context-Bm7PTBD1.js";
|
|
4
|
+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
4
5
|
import { readProviderTextResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
5
6
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
6
7
|
import { resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
8
|
+
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
|
|
7
9
|
import { callGatewayTool } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
8
|
-
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
9
10
|
//#region extensions/qqbot/src/engine/tools/channel-api.ts
|
|
10
11
|
/**
|
|
11
12
|
* QQ Channel API proxy tool core logic.
|
|
@@ -118,15 +119,6 @@ function validateDeleteConfirmation(params) {
|
|
|
118
119
|
if (isBulkAnnouncementDeletePath(params.path) && !params.bulkConfirmed) return "Deleting all announcements requires bulkConfirmed=true after a separate bulk-delete confirmation.";
|
|
119
120
|
return null;
|
|
120
121
|
}
|
|
121
|
-
function json$1(data) {
|
|
122
|
-
return {
|
|
123
|
-
content: [{
|
|
124
|
-
type: "text",
|
|
125
|
-
text: JSON.stringify(data, null, 2)
|
|
126
|
-
}],
|
|
127
|
-
details: data
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
122
|
/**
|
|
131
123
|
* Execute a channel API proxy request.
|
|
132
124
|
* 执行频道 API 代理请求。
|
|
@@ -136,8 +128,8 @@ function json$1(data) {
|
|
|
136
128
|
* response formatting suitable for AI tool output.
|
|
137
129
|
*/
|
|
138
130
|
async function executeChannelApi(params, options) {
|
|
139
|
-
if (!params.method) return
|
|
140
|
-
if (!params.path) return
|
|
131
|
+
if (!params.method) return jsonResult({ error: "method is required" });
|
|
132
|
+
if (!params.path) return jsonResult({ error: "path is required" });
|
|
141
133
|
const method = params.method.toUpperCase();
|
|
142
134
|
if (![
|
|
143
135
|
"GET",
|
|
@@ -145,14 +137,14 @@ async function executeChannelApi(params, options) {
|
|
|
145
137
|
"PUT",
|
|
146
138
|
"PATCH",
|
|
147
139
|
"DELETE"
|
|
148
|
-
].includes(method)) return
|
|
140
|
+
].includes(method)) return jsonResult({ error: `Unsupported HTTP method: ${method}. Allowed values: GET, POST, PUT, PATCH, DELETE` });
|
|
149
141
|
const pathError = validatePath(params.path);
|
|
150
|
-
if (pathError) return
|
|
142
|
+
if (pathError) return jsonResult({ error: pathError });
|
|
151
143
|
const confirmationError = validateDeleteConfirmation({
|
|
152
144
|
...params,
|
|
153
145
|
method
|
|
154
146
|
});
|
|
155
|
-
if (confirmationError) return
|
|
147
|
+
if (confirmationError) return jsonResult({
|
|
156
148
|
error: confirmationError,
|
|
157
149
|
path: params.path
|
|
158
150
|
});
|
|
@@ -191,13 +183,13 @@ async function executeChannelApi(params, options) {
|
|
|
191
183
|
clearTimeout(timeoutId);
|
|
192
184
|
if (err instanceof Error && err.name === "AbortError") {
|
|
193
185
|
debugError(`[qqbot-channel-api] <<< Request timeout after ${DEFAULT_TIMEOUT_MS}ms`);
|
|
194
|
-
return
|
|
186
|
+
return jsonResult({
|
|
195
187
|
error: `Request timed out after ${DEFAULT_TIMEOUT_MS}ms`,
|
|
196
188
|
path: params.path
|
|
197
189
|
});
|
|
198
190
|
}
|
|
199
191
|
debugError("[qqbot-channel-api] <<< Network error:", err);
|
|
200
|
-
return
|
|
192
|
+
return jsonResult({
|
|
201
193
|
error: `Network error: ${formatErrorMessage(err)}`,
|
|
202
194
|
path: params.path
|
|
203
195
|
});
|
|
@@ -208,12 +200,12 @@ async function executeChannelApi(params, options) {
|
|
|
208
200
|
debugLog(`[qqbot-channel-api] <<< Status: ${res.status} ${res.statusText}`);
|
|
209
201
|
const rawBody = res.ok ? await readProviderTextResponse(res, "QQ channel API response") : await readResponseTextLimited(res, CHANNEL_API_ERROR_BODY_LIMIT_BYTES);
|
|
210
202
|
if (!rawBody || rawBody.trim() === "") {
|
|
211
|
-
if (res.ok) return
|
|
203
|
+
if (res.ok) return jsonResult({
|
|
212
204
|
success: true,
|
|
213
205
|
status: res.status,
|
|
214
206
|
path: params.path
|
|
215
207
|
});
|
|
216
|
-
return
|
|
208
|
+
return jsonResult({
|
|
217
209
|
error: `API returned ${res.status} ${res.statusText}`,
|
|
218
210
|
status: res.status,
|
|
219
211
|
path: params.path
|
|
@@ -228,14 +220,14 @@ async function executeChannelApi(params, options) {
|
|
|
228
220
|
if (!res.ok) {
|
|
229
221
|
const errMsg = typeof parsed === "object" && parsed && "message" in parsed ? String(parsed.message) : `${res.status} ${res.statusText}`;
|
|
230
222
|
debugError(`[qqbot-channel-api] Error [${method} ${params.path}]: ${errMsg}`);
|
|
231
|
-
return
|
|
223
|
+
return jsonResult({
|
|
232
224
|
error: errMsg,
|
|
233
225
|
status: res.status,
|
|
234
226
|
path: params.path,
|
|
235
227
|
details: parsed
|
|
236
228
|
});
|
|
237
229
|
}
|
|
238
|
-
return
|
|
230
|
+
return jsonResult({
|
|
239
231
|
success: true,
|
|
240
232
|
status: res.status,
|
|
241
233
|
path: params.path,
|
|
@@ -245,7 +237,7 @@ async function executeChannelApi(params, options) {
|
|
|
245
237
|
await release?.();
|
|
246
238
|
}
|
|
247
239
|
} catch (err) {
|
|
248
|
-
return
|
|
240
|
+
return jsonResult({
|
|
249
241
|
error: formatErrorMessage(err),
|
|
250
242
|
path: params.path
|
|
251
243
|
});
|
|
@@ -274,7 +266,7 @@ function registerChannelTool(api) {
|
|
|
274
266
|
description: "Authenticated HTTP proxy for QQ Open Platform channel APIs. Use write and delete endpoints only after explicit user intent; DELETE requires confirmed=true, and bulk deletes require bulkConfirmed=true after confirming the exact target. Common endpoints: list guilds GET /users/@me/guilds | list channels GET /guilds/{guild_id}/channels | get channel GET /channels/{channel_id} | create channel POST /guilds/{guild_id}/channels | list members GET /guilds/{guild_id}/members?after=0&limit=100 | get member GET /guilds/{guild_id}/members/{user_id} | list threads GET /channels/{channel_id}/threads | create thread PUT /channels/{channel_id}/threads | create announce POST /guilds/{guild_id}/announces | create schedule POST /channels/{channel_id}/schedules. See the qqbot-channel skill for full endpoint details.",
|
|
275
267
|
parameters: ChannelApiSchema,
|
|
276
268
|
async execute(_toolCallId, params) {
|
|
277
|
-
const { getAccessToken } = await import("./sender-
|
|
269
|
+
const { getAccessToken } = await import("./sender-CjDuU-uz.js").then((n) => n._);
|
|
278
270
|
return executeChannelApi(params, { accessToken: await getAccessToken(account.appId, account.clientSecret) });
|
|
279
271
|
}
|
|
280
272
|
}, { name: "qqbot_channel_api" });
|
|
@@ -451,15 +443,6 @@ function formatDelay(ms) {
|
|
|
451
443
|
if (minutes === 0) return `${hours}h`;
|
|
452
444
|
return `${hours}h${minutes}m`;
|
|
453
445
|
}
|
|
454
|
-
function json(data) {
|
|
455
|
-
return {
|
|
456
|
-
content: [{
|
|
457
|
-
type: "text",
|
|
458
|
-
text: JSON.stringify(data, null, 2)
|
|
459
|
-
}],
|
|
460
|
-
details: data
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
446
|
function formatSchedulerError(error) {
|
|
464
447
|
return error instanceof Error ? error.message : String(error);
|
|
465
448
|
}
|
|
@@ -526,17 +509,17 @@ function prepareRemindCronAction(params, ctx = {}) {
|
|
|
526
509
|
}
|
|
527
510
|
async function executeScheduledRemind(params, ctx, scheduler) {
|
|
528
511
|
const plan = prepareRemindCronAction(params, ctx);
|
|
529
|
-
if (!plan.ok) return
|
|
512
|
+
if (!plan.ok) return jsonResult({ error: plan.error });
|
|
530
513
|
try {
|
|
531
514
|
const cronResult = await scheduler(plan.cronAction);
|
|
532
|
-
return
|
|
515
|
+
return jsonResult({
|
|
533
516
|
ok: true,
|
|
534
517
|
action: plan.action,
|
|
535
518
|
summary: plan.summary,
|
|
536
519
|
cronResult
|
|
537
520
|
});
|
|
538
521
|
} catch (error) {
|
|
539
|
-
return
|
|
522
|
+
return jsonResult({
|
|
540
523
|
error: `Failed to run Gateway cron action: ${formatSchedulerError(error)}`,
|
|
541
524
|
action: plan.action
|
|
542
525
|
});
|
package/dist/tools-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as registerQQBotTools } from "./tools-
|
|
1
|
+
import { t as registerQQBotTools } from "./tools-UJJ-tLHP.js";
|
|
2
2
|
export { registerQQBotTools };
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qqbot",
|
|
3
|
-
"version": "2026.7.1-beta.
|
|
3
|
+
"version": "2026.7.1-beta.4",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/qqbot",
|
|
9
|
-
"version": "2026.7.1-beta.
|
|
9
|
+
"version": "2026.7.1-beta.4",
|
|
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.7.1-beta.
|
|
18
|
+
"openclaw": ">=2026.7.1-beta.4"
|
|
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.7.1-beta.
|
|
3
|
+
"version": "2026.7.1-beta.4",
|
|
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.7.1-beta.
|
|
19
|
+
"openclaw": ">=2026.7.1-beta.4"
|
|
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.7.1-beta.
|
|
48
|
+
"pluginApi": ">=2026.7.1-beta.4"
|
|
49
49
|
},
|
|
50
50
|
"build": {
|
|
51
|
-
"openclawVersion": "2026.7.1-beta.
|
|
51
|
+
"openclawVersion": "2026.7.1-beta.4"
|
|
52
52
|
},
|
|
53
53
|
"release": {
|
|
54
54
|
"publishToClawHub": true,
|
|
@@ -9,7 +9,7 @@ metadata: { "openclaw": { "emoji": "📸", "requires": { "config": ["channels.qq
|
|
|
9
9
|
## 用法
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
<qqmedia
|
|
12
|
+
<qqmedia>{实际路径或URL}</qqmedia>
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
系统根据文件扩展名自动识别类型并路由:
|
|
@@ -18,7 +18,8 @@ metadata: { "openclaw": { "emoji": "📸", "requires": { "config": ["channels.qq
|
|
|
18
18
|
- `.silk/.wav/.mp3/.ogg/.aac/.flac` 等 → 语音
|
|
19
19
|
- `.mp4/.mov/.avi/.mkv/.webm` 等 → 视频
|
|
20
20
|
- 其他扩展名 → 文件
|
|
21
|
-
-
|
|
21
|
+
- 无扩展名的当前会话本地/host-read 媒体 → 按加载出的实际媒体类型路由
|
|
22
|
+
- 无扩展名的远程 URL → 可能按文件发送;如需图片/语音/视频,请提供能识别类型的 URL/路径或使用明确媒体标签
|
|
22
23
|
|
|
23
24
|
## 接收媒体
|
|
24
25
|
|
|
@@ -29,12 +30,14 @@ metadata: { "openclaw": { "emoji": "📸", "requires": { "config": ["channels.qq
|
|
|
29
30
|
|
|
30
31
|
## 规则
|
|
31
32
|
|
|
32
|
-
1.
|
|
33
|
-
2.
|
|
34
|
-
3.
|
|
35
|
-
4.
|
|
36
|
-
5.
|
|
37
|
-
6.
|
|
38
|
-
7.
|
|
39
|
-
8.
|
|
40
|
-
9.
|
|
33
|
+
1. **标签必须用开闭标签包裹实际路径或 URL**:`<qqmedia>{实际路径或URL}</qqmedia>`
|
|
34
|
+
2. **使用你实际看到的文件路径**:刚创建文件时,用创建结果显示的路径;只有当沙箱 workspace-write 创建结果实际显示 `/workspace/...` 时,才按原样使用该路径,例如 `<qqmedia>/workspace/report.pdf</qqmedia>`。
|
|
35
|
+
3. **附件路径直接使用上下文给出的路径**:如果路径来自会话【附件】上下文,不要改写成 `/workspace/...`。
|
|
36
|
+
4. **URL 可以直接发送**:例如 `<qqmedia>https://example.com/image.png</qqmedia>`。
|
|
37
|
+
5. **本地路径仍受安全根限制**:只能发送当前会话授权的 agent workspace、scoped media roots、OpenClaw 媒体目录或 QQBot 媒体目录内的文件;不要使用 `..` 逃出工作区。
|
|
38
|
+
6. **不要扫描或主动发送上下文之外的本地文件**:只使用用户提供、工具刚生成,或当前会话上下文明确给出的路径。
|
|
39
|
+
7. **文件大小上限**:图片 30MB / 视频 100MB / 文件 100MB / 语音 20MB
|
|
40
|
+
8. **你有能力发送本地图片/文件**,直接用标签包裹路径即可,**不要说"无法发送"**
|
|
41
|
+
9. 发送语音时不要重复语音中已朗读的文字
|
|
42
|
+
10. 多个媒体用多个标签
|
|
43
|
+
11. 以会话上下文中的能力说明为准(如未启用语音则不要发语音)
|