@ryantest/openclaw-qqbot 1.6.6-alpha.2 → 1.6.6-alpha.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/src/outbound-deliver.js +4 -3
- package/dist/src/utils/chunked-upload.js +1 -1
- package/dist/src/utils/media-send.d.ts +1 -0
- package/dist/src/utils/media-send.js +22 -0
- package/package.json +1 -1
- package/src/outbound-deliver.ts +4 -3
- package/src/utils/chunked-upload.ts +1 -1
- package/src/utils/media-send.ts +23 -0
|
@@ -154,7 +154,7 @@ export async function sendPlainReply(payload, replyText, event, actx, sendWithRe
|
|
|
154
154
|
});
|
|
155
155
|
if (result.error) {
|
|
156
156
|
log?.error(`${prefix} sendMedia(auto) error for ${mediaPath}: ${result.error}`);
|
|
157
|
-
await sendTextChunks(
|
|
157
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
158
158
|
}
|
|
159
159
|
else {
|
|
160
160
|
log?.info(`${prefix} Sent local media: ${mediaPath}`);
|
|
@@ -162,7 +162,7 @@ export async function sendPlainReply(payload, replyText, event, actx, sendWithRe
|
|
|
162
162
|
}
|
|
163
163
|
catch (err) {
|
|
164
164
|
log?.error(`${prefix} sendMedia(auto) failed for ${mediaPath}: ${err}`);
|
|
165
|
-
await sendTextChunks(
|
|
165
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
@@ -183,7 +183,7 @@ export async function sendPlainReply(payload, replyText, event, actx, sendWithRe
|
|
|
183
183
|
});
|
|
184
184
|
if (result.error) {
|
|
185
185
|
log?.error(`${prefix} Tool media forward error: ${result.error}`);
|
|
186
|
-
await sendTextChunks(
|
|
186
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
187
187
|
}
|
|
188
188
|
else {
|
|
189
189
|
log?.info(`${prefix} Forwarded tool media: ${mediaUrl.slice(0, 80)}...`);
|
|
@@ -191,6 +191,7 @@ export async function sendPlainReply(payload, replyText, event, actx, sendWithRe
|
|
|
191
191
|
}
|
|
192
192
|
catch (err) {
|
|
193
193
|
log?.error(`${prefix} Tool media forward failed: ${err}`);
|
|
194
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
197
|
}
|
|
@@ -17,7 +17,7 @@ import * as fs from "node:fs";
|
|
|
17
17
|
import { c2cUploadPrepare, c2cUploadPartFinish, c2cCompleteUpload, groupUploadPrepare, groupUploadPartFinish, groupCompleteUpload, getAccessToken, } from "../api.js";
|
|
18
18
|
import { formatFileSize } from "./file-utils.js";
|
|
19
19
|
/** 分片上传并发控制:最多同时上传 N 个分片 */
|
|
20
|
-
const MAX_CONCURRENT_PARTS =
|
|
20
|
+
const MAX_CONCURRENT_PARTS = 1;
|
|
21
21
|
/** 单个分片上传超时(毫秒)— 5 分钟,兼容低带宽场景 */
|
|
22
22
|
const PART_UPLOAD_TIMEOUT = 300_000;
|
|
23
23
|
/** 单个分片上传最大重试次数 */
|
|
@@ -125,6 +125,7 @@ export declare function parseMediaTagsToSendQueue(text: string, log?: {
|
|
|
125
125
|
*
|
|
126
126
|
* 遍历 sendQueue,按类型调用对应的发送函数。
|
|
127
127
|
* 文本项通过 onSendText 回调处理(不同场景的文本发送方式不同)。
|
|
128
|
+
* 媒体发送失败时,通过 onSendText 发送兜底文本通知用户。
|
|
128
129
|
*/
|
|
129
130
|
export declare function executeSendQueue(queue: SendQueueItem[], ctx: MediaSendContext, options?: {
|
|
130
131
|
/** 文本发送回调(每种场景的文本发送方式不同) */
|
|
@@ -221,10 +221,24 @@ export function parseMediaTagsToSendQueue(text, log) {
|
|
|
221
221
|
*
|
|
222
222
|
* 遍历 sendQueue,按类型调用对应的发送函数。
|
|
223
223
|
* 文本项通过 onSendText 回调处理(不同场景的文本发送方式不同)。
|
|
224
|
+
* 媒体发送失败时,通过 onSendText 发送兜底文本通知用户。
|
|
224
225
|
*/
|
|
225
226
|
export async function executeSendQueue(queue, ctx, options = {}) {
|
|
226
227
|
const { mediaTarget, qualifiedTarget, account, replyToId, log } = ctx;
|
|
227
228
|
const prefix = mediaTarget.logPrefix ?? `[qqbot:${account.accountId}]`;
|
|
229
|
+
/** 媒体发送失败时的兜底:通过 onSendText 发送错误文本给用户 */
|
|
230
|
+
const sendFallbackText = async (errorMsg) => {
|
|
231
|
+
if (!options.onSendText) {
|
|
232
|
+
log?.info(`${prefix} executeSendQueue: no onSendText handler, cannot send fallback text`);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
await options.onSendText(errorMsg);
|
|
237
|
+
}
|
|
238
|
+
catch (fallbackErr) {
|
|
239
|
+
log?.error(`${prefix} executeSendQueue: fallback text send failed: ${fallbackErr}`);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
228
242
|
for (const item of queue) {
|
|
229
243
|
try {
|
|
230
244
|
if (item.type === "text") {
|
|
@@ -241,10 +255,12 @@ export async function executeSendQueue(queue, ctx, options = {}) {
|
|
|
241
255
|
continue;
|
|
242
256
|
}
|
|
243
257
|
log?.info(`${prefix} executeSendQueue: sending ${item.type}: ${item.content.slice(0, 80)}...`);
|
|
258
|
+
const FALLBACK_MSG = "发送失败,请稍后重试。";
|
|
244
259
|
if (item.type === "image") {
|
|
245
260
|
const result = await sendPhoto(mediaTarget, item.content);
|
|
246
261
|
if (result.error) {
|
|
247
262
|
log?.error(`${prefix} sendPhoto error: ${result.error}`);
|
|
263
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
248
264
|
}
|
|
249
265
|
}
|
|
250
266
|
else if (item.type === "voice") {
|
|
@@ -259,22 +275,26 @@ export async function executeSendQueue(queue, ctx, options = {}) {
|
|
|
259
275
|
]);
|
|
260
276
|
if (result.error) {
|
|
261
277
|
log?.error(`${prefix} sendVoice error: ${result.error}`);
|
|
278
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
262
279
|
}
|
|
263
280
|
}
|
|
264
281
|
catch (err) {
|
|
265
282
|
log?.error(`${prefix} sendVoice unexpected error: ${err}`);
|
|
283
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
266
284
|
}
|
|
267
285
|
}
|
|
268
286
|
else if (item.type === "video") {
|
|
269
287
|
const result = await sendVideoMsg(mediaTarget, item.content);
|
|
270
288
|
if (result.error) {
|
|
271
289
|
log?.error(`${prefix} sendVideoMsg error: ${result.error}`);
|
|
290
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
272
291
|
}
|
|
273
292
|
}
|
|
274
293
|
else if (item.type === "file") {
|
|
275
294
|
const result = await sendDocument(mediaTarget, item.content);
|
|
276
295
|
if (result.error) {
|
|
277
296
|
log?.error(`${prefix} sendDocument error: ${result.error}`);
|
|
297
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
278
298
|
}
|
|
279
299
|
}
|
|
280
300
|
else if (item.type === "media") {
|
|
@@ -288,11 +308,13 @@ export async function executeSendQueue(queue, ctx, options = {}) {
|
|
|
288
308
|
});
|
|
289
309
|
if (result.error) {
|
|
290
310
|
log?.error(`${prefix} sendMedia(auto) error: ${result.error}`);
|
|
311
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
291
312
|
}
|
|
292
313
|
}
|
|
293
314
|
}
|
|
294
315
|
catch (err) {
|
|
295
316
|
log?.error(`${prefix} executeSendQueue: failed to send ${item.type}: ${err}`);
|
|
317
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
296
318
|
}
|
|
297
319
|
}
|
|
298
320
|
}
|
package/package.json
CHANGED
package/src/outbound-deliver.ts
CHANGED
|
@@ -217,13 +217,13 @@ export async function sendPlainReply(
|
|
|
217
217
|
});
|
|
218
218
|
if (result.error) {
|
|
219
219
|
log?.error(`${prefix} sendMedia(auto) error for ${mediaPath}: ${result.error}`);
|
|
220
|
-
await sendTextChunks(
|
|
220
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
221
221
|
} else {
|
|
222
222
|
log?.info(`${prefix} Sent local media: ${mediaPath}`);
|
|
223
223
|
}
|
|
224
224
|
} catch (err) {
|
|
225
225
|
log?.error(`${prefix} sendMedia(auto) failed for ${mediaPath}: ${err}`);
|
|
226
|
-
await sendTextChunks(
|
|
226
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
}
|
|
@@ -245,12 +245,13 @@ export async function sendPlainReply(
|
|
|
245
245
|
});
|
|
246
246
|
if (result.error) {
|
|
247
247
|
log?.error(`${prefix} Tool media forward error: ${result.error}`);
|
|
248
|
-
await sendTextChunks(
|
|
248
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
249
249
|
} else {
|
|
250
250
|
log?.info(`${prefix} Forwarded tool media: ${mediaUrl.slice(0, 80)}...`);
|
|
251
251
|
}
|
|
252
252
|
} catch (err) {
|
|
253
253
|
log?.error(`${prefix} Tool media forward failed: ${err}`);
|
|
254
|
+
await sendTextChunks("发送失败,请稍后重试。", event, actx, sendWithRetry, consumeQuoteRef);
|
|
254
255
|
}
|
|
255
256
|
}
|
|
256
257
|
}
|
package/src/utils/media-send.ts
CHANGED
|
@@ -335,6 +335,7 @@ export function parseMediaTagsToSendQueue(
|
|
|
335
335
|
*
|
|
336
336
|
* 遍历 sendQueue,按类型调用对应的发送函数。
|
|
337
337
|
* 文本项通过 onSendText 回调处理(不同场景的文本发送方式不同)。
|
|
338
|
+
* 媒体发送失败时,通过 onSendText 发送兜底文本通知用户。
|
|
338
339
|
*/
|
|
339
340
|
export async function executeSendQueue(
|
|
340
341
|
queue: SendQueueItem[],
|
|
@@ -349,6 +350,19 @@ export async function executeSendQueue(
|
|
|
349
350
|
const { mediaTarget, qualifiedTarget, account, replyToId, log } = ctx;
|
|
350
351
|
const prefix = mediaTarget.logPrefix ?? `[qqbot:${account.accountId}]`;
|
|
351
352
|
|
|
353
|
+
/** 媒体发送失败时的兜底:通过 onSendText 发送错误文本给用户 */
|
|
354
|
+
const sendFallbackText = async (errorMsg: string): Promise<void> => {
|
|
355
|
+
if (!options.onSendText) {
|
|
356
|
+
log?.info(`${prefix} executeSendQueue: no onSendText handler, cannot send fallback text`);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
await options.onSendText(errorMsg);
|
|
361
|
+
} catch (fallbackErr) {
|
|
362
|
+
log?.error(`${prefix} executeSendQueue: fallback text send failed: ${fallbackErr}`);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
352
366
|
for (const item of queue) {
|
|
353
367
|
try {
|
|
354
368
|
if (item.type === "text") {
|
|
@@ -366,10 +380,13 @@ export async function executeSendQueue(
|
|
|
366
380
|
|
|
367
381
|
log?.info(`${prefix} executeSendQueue: sending ${item.type}: ${item.content.slice(0, 80)}...`);
|
|
368
382
|
|
|
383
|
+
const FALLBACK_MSG = "发送失败,请稍后重试。";
|
|
384
|
+
|
|
369
385
|
if (item.type === "image") {
|
|
370
386
|
const result = await sendPhoto(mediaTarget, item.content);
|
|
371
387
|
if (result.error) {
|
|
372
388
|
log?.error(`${prefix} sendPhoto error: ${result.error}`);
|
|
389
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
373
390
|
}
|
|
374
391
|
} else if (item.type === "voice") {
|
|
375
392
|
const uploadFormats =
|
|
@@ -390,19 +407,23 @@ export async function executeSendQueue(
|
|
|
390
407
|
]);
|
|
391
408
|
if (result.error) {
|
|
392
409
|
log?.error(`${prefix} sendVoice error: ${result.error}`);
|
|
410
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
393
411
|
}
|
|
394
412
|
} catch (err) {
|
|
395
413
|
log?.error(`${prefix} sendVoice unexpected error: ${err}`);
|
|
414
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
396
415
|
}
|
|
397
416
|
} else if (item.type === "video") {
|
|
398
417
|
const result = await sendVideoMsg(mediaTarget, item.content);
|
|
399
418
|
if (result.error) {
|
|
400
419
|
log?.error(`${prefix} sendVideoMsg error: ${result.error}`);
|
|
420
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
401
421
|
}
|
|
402
422
|
} else if (item.type === "file") {
|
|
403
423
|
const result = await sendDocument(mediaTarget, item.content);
|
|
404
424
|
if (result.error) {
|
|
405
425
|
log?.error(`${prefix} sendDocument error: ${result.error}`);
|
|
426
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
406
427
|
}
|
|
407
428
|
} else if (item.type === "media") {
|
|
408
429
|
const result = await sendMediaAuto({
|
|
@@ -415,10 +436,12 @@ export async function executeSendQueue(
|
|
|
415
436
|
});
|
|
416
437
|
if (result.error) {
|
|
417
438
|
log?.error(`${prefix} sendMedia(auto) error: ${result.error}`);
|
|
439
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
418
440
|
}
|
|
419
441
|
}
|
|
420
442
|
} catch (err) {
|
|
421
443
|
log?.error(`${prefix} executeSendQueue: failed to send ${item.type}: ${err}`);
|
|
444
|
+
await sendFallbackText(FALLBACK_MSG);
|
|
422
445
|
}
|
|
423
446
|
}
|
|
424
447
|
}
|