@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.
@@ -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(result.error, event, actx, sendWithRetry, consumeQuoteRef);
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(`发送媒体失败:${err}`, event, actx, sendWithRetry, consumeQuoteRef);
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(result.error, event, actx, sendWithRetry, consumeQuoteRef);
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 = 2;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryantest/openclaw-qqbot",
3
- "version": "1.6.6-alpha.2",
3
+ "version": "1.6.6-alpha.4",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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(result.error, event, actx, sendWithRetry, consumeQuoteRef);
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(`发送媒体失败:${err}`, event, actx, sendWithRetry, consumeQuoteRef);
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(result.error, event, actx, sendWithRetry, consumeQuoteRef);
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
  }
@@ -31,7 +31,7 @@ import {
31
31
  import { formatFileSize } from "./file-utils.js";
32
32
 
33
33
  /** 分片上传并发控制:最多同时上传 N 个分片 */
34
- const MAX_CONCURRENT_PARTS = 2;
34
+ const MAX_CONCURRENT_PARTS = 1;
35
35
 
36
36
  /** 单个分片上传超时(毫秒)— 5 分钟,兼容低带宽场景 */
37
37
  const PART_UPLOAD_TIMEOUT = 300_000;
@@ -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
  }