mioku-plugin-chat 2.10.1 → 3.0.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/configs/base.ts +1 -1
- package/context.ts +2 -2
- package/core/base.ts +113 -82
- package/core/chat-engine.ts +44 -23
- package/core/chat-turn.ts +11 -11
- package/core/media/audio.ts +4 -4
- package/core/media/gif-extractor.ts +4 -4
- package/core/media/history-media.ts +11 -16
- package/core/media/image-analyzer.ts +1 -1
- package/core/media/image-compress.ts +1 -1
- package/core/media/markdown-message.ts +22 -0
- package/core/media/segment.ts +10 -14
- package/core/multimodal.ts +18 -13
- package/core/prompt.ts +12 -10
- package/core/tools/info.ts +8 -7
- package/core/tools/web.ts +96 -57
- package/core/tools.ts +1 -1
- package/core/web/searxng.ts +1 -1
- package/core/web/web-reader.ts +2 -2
- package/db.ts +6 -3
- package/handlers/idle-debug.ts +4 -4
- package/handlers/message.ts +44 -29
- package/handlers/poke.ts +22 -16
- package/humanize/emoji-agent.ts +1 -1
- package/humanize/emotion-agent.ts +1 -1
- package/humanize/expression.ts +1 -1
- package/humanize/memory.ts +1 -1
- package/humanize/planner.ts +1 -1
- package/humanize/topic.ts +1 -1
- package/index.ts +3 -3
- package/manage/cleanup.ts +1 -1
- package/manage/cooldown.ts +5 -5
- package/manage/group-structured-history.ts +1 -1
- package/manage/idle-check.ts +5 -5
- package/manage/queue-processor.ts +5 -5
- package/manage/types.ts +39 -15
- package/package.json +3 -5
- package/types.ts +5 -5
- package/utils/message.ts +111 -66
- package/utils/queue.ts +7 -6
package/configs/base.ts
CHANGED
package/context.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MiokuContext } from "mioku";
|
|
2
2
|
import type { AIInstance, AIModelRole, AIService } from "mioku";
|
|
3
3
|
import type { ChatConfig } from "./types";
|
|
4
4
|
import type { ChatDatabase } from "./db";
|
|
@@ -35,7 +35,7 @@ import type { AudioServiceApi } from "mioku-service-audio";
|
|
|
35
35
|
import type { ChatMessage } from "./types";
|
|
36
36
|
|
|
37
37
|
export interface ChatPluginContext {
|
|
38
|
-
ctx:
|
|
38
|
+
ctx: MiokuContext;
|
|
39
39
|
defaultConfig: ChatConfig;
|
|
40
40
|
configProvider: ChatConfigProvider;
|
|
41
41
|
getConfig: (groupId?: number) => Promise<ChatConfig>;
|
package/core/base.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { logger } from "
|
|
1
|
+
import type { Bot, MiokuContext } from "mioku";
|
|
2
|
+
import { createGroupRef, logger } from "mioku";
|
|
3
3
|
import type { SkillPermissionRole } from "mioku";
|
|
4
4
|
import type { AIInstance, AIService } from "mioku";
|
|
5
5
|
import type { ScreenshotService } from "mioku";
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from "./media/markdown-message";
|
|
25
25
|
|
|
26
26
|
export interface SendAIResponseOptions {
|
|
27
|
-
ctx:
|
|
27
|
+
ctx: MiokuContext;
|
|
28
28
|
groupId: number;
|
|
29
29
|
messages: string[];
|
|
30
30
|
config: ChatConfig;
|
|
@@ -79,7 +79,7 @@ async function waitTypingDelay(
|
|
|
79
79
|
export async function sendAIResponse(
|
|
80
80
|
options: SendAIResponseOptions,
|
|
81
81
|
selfId: number,
|
|
82
|
-
): Promise<
|
|
82
|
+
): Promise<Array<string | undefined>> {
|
|
83
83
|
const {
|
|
84
84
|
ctx,
|
|
85
85
|
groupId,
|
|
@@ -96,17 +96,25 @@ export async function sendAIResponse(
|
|
|
96
96
|
ctx.logger.error(
|
|
97
97
|
`[sendAIResponse] bot ${String(selfId)} not found, skip sending group message`,
|
|
98
98
|
);
|
|
99
|
-
return;
|
|
99
|
+
return [];
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
if (messages.length === 0) return;
|
|
102
|
+
if (messages.length === 0) return [];
|
|
103
|
+
|
|
104
|
+
const sentMessageIds: Array<string | undefined> = new Array(messages.length);
|
|
105
|
+
const recordSentId = (messageIndex: number, messageId?: string) => {
|
|
106
|
+
if (!messageId) return;
|
|
107
|
+
if (messageIndex >= 0 && messageIndex < messages.length) {
|
|
108
|
+
sentMessageIds[messageIndex] ??= messageId;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
103
111
|
|
|
104
112
|
for (let i = 0; i < messages.length; i++) {
|
|
105
113
|
if (sentIndices?.has(i)) continue;
|
|
106
114
|
|
|
107
115
|
const expandedLines = expandOutgoingLines(messages[i]);
|
|
108
116
|
|
|
109
|
-
let pendingReply:
|
|
117
|
+
let pendingReply: string | undefined;
|
|
110
118
|
let lastDelayBasisText = "";
|
|
111
119
|
|
|
112
120
|
for (let j = 0; j < expandedLines.length; j++) {
|
|
@@ -141,10 +149,7 @@ export async function sendAIResponse(
|
|
|
141
149
|
|
|
142
150
|
if (pokeUsers.length > 0) {
|
|
143
151
|
for (const pokeId of pokeUsers) {
|
|
144
|
-
await bot.
|
|
145
|
-
group_id: groupId,
|
|
146
|
-
user_id: pokeId,
|
|
147
|
-
});
|
|
152
|
+
await bot.pokeMember(String(groupId), String(pokeId));
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
|
@@ -152,12 +157,13 @@ export async function sendAIResponse(
|
|
|
152
157
|
|
|
153
158
|
const finalQuoteId = pendingReply;
|
|
154
159
|
if (finalQuoteId !== undefined) {
|
|
155
|
-
lineSegments.push(
|
|
160
|
+
lineSegments.push(ctx.segment.reply(finalQuoteId));
|
|
156
161
|
pendingReply = undefined;
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
for (const atId of atUsers) {
|
|
160
|
-
|
|
165
|
+
if (String(atId) === String(selfId)) continue;
|
|
166
|
+
lineSegments.push(ctx.segment.at(String(atId)));
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
if (markdownContent) {
|
|
@@ -178,13 +184,11 @@ export async function sendAIResponse(
|
|
|
178
184
|
(imageSource?: string) => {
|
|
179
185
|
const segments: any[] = [];
|
|
180
186
|
if (finalQuoteIdForImage !== undefined) {
|
|
181
|
-
segments.push(
|
|
182
|
-
type: "reply",
|
|
183
|
-
id: String(finalQuoteIdForImage),
|
|
184
|
-
});
|
|
187
|
+
segments.push(ctx.segment.reply(finalQuoteIdForImage));
|
|
185
188
|
}
|
|
186
189
|
for (const atId of atUsers) {
|
|
187
|
-
|
|
190
|
+
if (String(atId) === String(selfId)) continue;
|
|
191
|
+
segments.push(ctx.segment.at(String(atId)));
|
|
188
192
|
}
|
|
189
193
|
segments.push(
|
|
190
194
|
ctx.segment.image(
|
|
@@ -194,7 +198,7 @@ export async function sendAIResponse(
|
|
|
194
198
|
return segments;
|
|
195
199
|
},
|
|
196
200
|
imagePath,
|
|
197
|
-
);
|
|
201
|
+
).then((sentId) => recordSentId(i, sentId));
|
|
198
202
|
lastDelayBasisText = summarizeMarkdown(markdownContent);
|
|
199
203
|
if (typingDelayEnabled && j < expandedLines.length - 1) {
|
|
200
204
|
const delayMs = calculateTypingDelayMs(lastDelayBasisText || line);
|
|
@@ -217,11 +221,15 @@ export async function sendAIResponse(
|
|
|
217
221
|
lineSegments.push(ctx.segment.text(fallbackText));
|
|
218
222
|
}
|
|
219
223
|
if (audioSource) {
|
|
220
|
-
lineSegments.push(ctx.segment.record
|
|
224
|
+
lineSegments.push(ctx.segment.raw("record", { file: audioSource }));
|
|
221
225
|
}
|
|
222
226
|
|
|
223
227
|
if (lineSegments.length > 0) {
|
|
224
|
-
await bot.
|
|
228
|
+
const sent = await bot.sendMessage(
|
|
229
|
+
{ type: "group", group_id: groupId },
|
|
230
|
+
lineSegments,
|
|
231
|
+
);
|
|
232
|
+
recordSentId(i, sent?.message_id);
|
|
225
233
|
lastDelayBasisText = sendableText || fallbackText || audioText || line;
|
|
226
234
|
}
|
|
227
235
|
|
|
@@ -238,10 +246,12 @@ export async function sendAIResponse(
|
|
|
238
246
|
|
|
239
247
|
await onLineSent?.();
|
|
240
248
|
}
|
|
249
|
+
|
|
250
|
+
return sentMessageIds;
|
|
241
251
|
}
|
|
242
252
|
|
|
243
253
|
export async function sendMessage(
|
|
244
|
-
ctx:
|
|
254
|
+
ctx: MiokuContext,
|
|
245
255
|
groupId: number | undefined,
|
|
246
256
|
userId: number,
|
|
247
257
|
text: string,
|
|
@@ -263,7 +273,7 @@ export async function sendMessage(
|
|
|
263
273
|
// 应用错别字生成器
|
|
264
274
|
const expandedLines = expandOutgoingLines(text);
|
|
265
275
|
|
|
266
|
-
let pendingReply:
|
|
276
|
+
let pendingReply: string | undefined;
|
|
267
277
|
let lastDelayBasisText = "";
|
|
268
278
|
|
|
269
279
|
for (let j = 0; j < expandedLines.length; j++) {
|
|
@@ -296,13 +306,9 @@ export async function sendMessage(
|
|
|
296
306
|
continue;
|
|
297
307
|
}
|
|
298
308
|
|
|
299
|
-
// 戳人 - 立即执行
|
|
300
309
|
if (groupId && pokeUsers.length > 0) {
|
|
301
310
|
for (const pokeId of pokeUsers) {
|
|
302
|
-
await bot.
|
|
303
|
-
group_id: groupId,
|
|
304
|
-
user_id: pokeId,
|
|
305
|
-
});
|
|
311
|
+
await bot.pokeMember(String(groupId), String(pokeId));
|
|
306
312
|
}
|
|
307
313
|
}
|
|
308
314
|
|
|
@@ -327,14 +333,11 @@ export async function sendMessage(
|
|
|
327
333
|
(imageSource?: string) => {
|
|
328
334
|
const segments: any[] = [];
|
|
329
335
|
if (finalQuoteIdForImage !== undefined) {
|
|
330
|
-
segments.push(
|
|
331
|
-
type: "reply",
|
|
332
|
-
id: String(finalQuoteIdForImage),
|
|
333
|
-
});
|
|
336
|
+
segments.push(ctx.segment.reply(finalQuoteIdForImage));
|
|
334
337
|
}
|
|
335
338
|
for (const atId of atUsers) {
|
|
336
339
|
if (String(atId) !== String(selfId)) {
|
|
337
|
-
segments.push(ctx.segment.at(atId));
|
|
340
|
+
segments.push(ctx.segment.at(String(atId)));
|
|
338
341
|
}
|
|
339
342
|
}
|
|
340
343
|
segments.push(
|
|
@@ -366,13 +369,13 @@ export async function sendMessage(
|
|
|
366
369
|
const sendableText = markdownContent ?? cleanText;
|
|
367
370
|
const segments: any[] = [];
|
|
368
371
|
if (pendingReply !== undefined) {
|
|
369
|
-
segments.push(
|
|
372
|
+
segments.push(ctx.segment.reply(pendingReply));
|
|
370
373
|
pendingReply = undefined;
|
|
371
374
|
}
|
|
372
375
|
if (markdownContent) {
|
|
373
376
|
for (const atId of atUsers) {
|
|
374
377
|
if (String(atId) !== String(selfId)) {
|
|
375
|
-
segments.push(ctx.segment.at(atId));
|
|
378
|
+
segments.push(ctx.segment.at(String(atId)));
|
|
376
379
|
}
|
|
377
380
|
}
|
|
378
381
|
if (sendableText) {
|
|
@@ -381,11 +384,14 @@ export async function sendMessage(
|
|
|
381
384
|
segments.push(ctx.segment.text(fallbackText));
|
|
382
385
|
}
|
|
383
386
|
if (audioSource) {
|
|
384
|
-
segments.push(ctx.segment.record
|
|
387
|
+
segments.push(ctx.segment.raw("record", { file: audioSource }));
|
|
385
388
|
}
|
|
386
389
|
|
|
387
390
|
if (segments.length > 0 && groupId) {
|
|
388
|
-
await bot.
|
|
391
|
+
await bot.sendMessage(
|
|
392
|
+
{ type: "group", group_id: groupId },
|
|
393
|
+
segments,
|
|
394
|
+
);
|
|
389
395
|
lastDelayBasisText =
|
|
390
396
|
sendableText || fallbackText || audioText || line;
|
|
391
397
|
}
|
|
@@ -398,7 +404,7 @@ export async function sendMessage(
|
|
|
398
404
|
// 有 @ 用户时,构建消息保持原始位置
|
|
399
405
|
// 先将原始行按 @ 标记分割,然后重新构建
|
|
400
406
|
let remaining = line;
|
|
401
|
-
const atPattern = /\[at:
|
|
407
|
+
const atPattern = /\[at: \d+\]/g;
|
|
402
408
|
|
|
403
409
|
let lastIndex = 0;
|
|
404
410
|
let match;
|
|
@@ -407,18 +413,18 @@ export async function sendMessage(
|
|
|
407
413
|
const beforeAt = remaining.slice(lastIndex, match.index);
|
|
408
414
|
if (beforeAt) {
|
|
409
415
|
const cleaned = beforeAt
|
|
410
|
-
.replace(/\[reply
|
|
416
|
+
.replace(/\[reply:[^\]\n]+\]/g, "")
|
|
411
417
|
.replace(/\[poke:\d+\]/g, "")
|
|
412
418
|
.replace(/\[audio:[^\]]+\]/gi, "")
|
|
413
419
|
.trim();
|
|
414
420
|
if (cleaned) {
|
|
415
|
-
segments.push(
|
|
421
|
+
segments.push(ctx.segment.text(cleaned));
|
|
416
422
|
}
|
|
417
423
|
}
|
|
418
424
|
|
|
419
425
|
const atId = match[1];
|
|
420
426
|
if (String(atId) !== String(selfId)) {
|
|
421
|
-
segments.push(ctx.segment.at(atId));
|
|
427
|
+
segments.push(ctx.segment.at(String(atId)));
|
|
422
428
|
}
|
|
423
429
|
|
|
424
430
|
lastIndex = match.index + match[0].length;
|
|
@@ -428,25 +434,28 @@ export async function sendMessage(
|
|
|
428
434
|
const afterAt = remaining.slice(lastIndex);
|
|
429
435
|
if (afterAt) {
|
|
430
436
|
const cleaned = afterAt
|
|
431
|
-
.replace(/\[reply
|
|
437
|
+
.replace(/\[reply:[^\]\n]+\]/g, "")
|
|
432
438
|
.replace(/\[poke:\d+\]/g, "")
|
|
433
439
|
.replace(/\[audio:[^\]]+\]/gi, "")
|
|
434
440
|
.trim();
|
|
435
441
|
if (cleaned) {
|
|
436
|
-
segments.push(
|
|
442
|
+
segments.push(ctx.segment.text(cleaned));
|
|
437
443
|
}
|
|
438
444
|
}
|
|
439
445
|
|
|
440
446
|
if (audioSource) {
|
|
441
|
-
segments.push(ctx.segment.record
|
|
447
|
+
segments.push(ctx.segment.raw("record", { file: audioSource }));
|
|
442
448
|
} else if (fallbackText) {
|
|
443
|
-
segments.push(
|
|
449
|
+
segments.push(ctx.segment.text(fallbackText));
|
|
444
450
|
}
|
|
445
451
|
|
|
446
452
|
// 发送消息
|
|
447
453
|
if (segments.length > 0) {
|
|
448
454
|
if (groupId) {
|
|
449
|
-
await bot.
|
|
455
|
+
await bot.sendMessage(
|
|
456
|
+
{ type: "group", group_id: groupId },
|
|
457
|
+
segments,
|
|
458
|
+
);
|
|
450
459
|
lastDelayBasisText =
|
|
451
460
|
sendableText || fallbackText || audioText || line;
|
|
452
461
|
}
|
|
@@ -462,7 +471,7 @@ export async function sendMessage(
|
|
|
462
471
|
) {
|
|
463
472
|
const sendSegments: any[] = [];
|
|
464
473
|
if (pendingReply !== undefined) {
|
|
465
|
-
sendSegments.push(
|
|
474
|
+
sendSegments.push(ctx.segment.reply(pendingReply));
|
|
466
475
|
pendingReply = undefined;
|
|
467
476
|
}
|
|
468
477
|
if (sendableText) {
|
|
@@ -471,7 +480,7 @@ export async function sendMessage(
|
|
|
471
480
|
sendSegments.push(ctx.segment.text(fallbackText));
|
|
472
481
|
}
|
|
473
482
|
if (audioSource) {
|
|
474
|
-
sendSegments.push(ctx.segment.record
|
|
483
|
+
sendSegments.push(ctx.segment.raw("record", { file: audioSource }));
|
|
475
484
|
}
|
|
476
485
|
if (sendSegments.length > 0) {
|
|
477
486
|
await dispatchSegments(bot, groupId, userId, () => sendSegments);
|
|
@@ -521,13 +530,13 @@ function expandOutgoingLines(text: string): string[] {
|
|
|
521
530
|
|
|
522
531
|
function normalizeActionLineBreaks(text: string): string {
|
|
523
532
|
return String(text || "").replace(
|
|
524
|
-
/\\\s*(?=(?:\[\]|\[emotion:[^\]]+\]|\[audio:[^\]]+\]|\[reply
|
|
533
|
+
/\\\s*(?=(?:\[\]|\[emotion:[^\]]+\]|\[audio:[^\]]+\]|\[reply:[^\]\n]+\]))/gi,
|
|
525
534
|
"\n",
|
|
526
535
|
);
|
|
527
536
|
}
|
|
528
537
|
|
|
529
538
|
async function buildMarkdownImage(
|
|
530
|
-
ctx:
|
|
539
|
+
ctx: MiokuContext,
|
|
531
540
|
markdownContent: string,
|
|
532
541
|
screenshotService: ScreenshotService | undefined,
|
|
533
542
|
enableMarkdownScreenshot: boolean,
|
|
@@ -550,9 +559,10 @@ async function dispatchSegments(
|
|
|
550
559
|
userId: number | undefined,
|
|
551
560
|
buildSegments: (imageSource?: string) => any[],
|
|
552
561
|
fallbackImagePath?: string,
|
|
553
|
-
): Promise<
|
|
562
|
+
): Promise<string | undefined> {
|
|
554
563
|
try {
|
|
555
|
-
await sendByTarget(bot, groupId, userId, buildSegments());
|
|
564
|
+
const sent = await sendByTarget(bot, groupId, userId, buildSegments());
|
|
565
|
+
return sent?.message_id;
|
|
556
566
|
} catch (error) {
|
|
557
567
|
if (!fallbackImagePath || !isLocalFilePath(fallbackImagePath)) {
|
|
558
568
|
throw error;
|
|
@@ -561,24 +571,34 @@ async function dispatchSegments(
|
|
|
561
571
|
const fsPromises = await import("fs/promises");
|
|
562
572
|
const buffer = await fsPromises.readFile(fallbackImagePath);
|
|
563
573
|
const base64Image = `base64://${buffer.toString("base64")}`;
|
|
564
|
-
|
|
574
|
+
const sent = await sendByTarget(
|
|
575
|
+
bot,
|
|
576
|
+
groupId,
|
|
577
|
+
userId,
|
|
578
|
+
buildSegments(base64Image),
|
|
579
|
+
);
|
|
580
|
+
return sent?.message_id;
|
|
565
581
|
}
|
|
566
582
|
}
|
|
567
583
|
|
|
568
584
|
async function sendByTarget(
|
|
569
|
-
bot:
|
|
585
|
+
bot: Bot,
|
|
570
586
|
groupId: number | undefined,
|
|
571
587
|
userId: number | undefined,
|
|
572
|
-
segments: any[],
|
|
573
|
-
): Promise<
|
|
588
|
+
segments: readonly any[],
|
|
589
|
+
): Promise<import("mioku").SentMessage | undefined> {
|
|
574
590
|
if (groupId) {
|
|
575
|
-
await bot.
|
|
576
|
-
|
|
591
|
+
return await bot.sendMessage(
|
|
592
|
+
{ type: "group", group_id: groupId },
|
|
593
|
+
segments,
|
|
594
|
+
);
|
|
577
595
|
}
|
|
578
596
|
|
|
579
597
|
if (userId) {
|
|
580
|
-
await bot.
|
|
581
|
-
|
|
598
|
+
return await bot.sendMessage(
|
|
599
|
+
{ type: "private", user_id: userId },
|
|
600
|
+
segments,
|
|
601
|
+
);
|
|
582
602
|
}
|
|
583
603
|
|
|
584
604
|
throw new Error("No valid message target");
|
|
@@ -612,11 +632,11 @@ function isLocalFilePath(value: string): boolean {
|
|
|
612
632
|
}
|
|
613
633
|
|
|
614
634
|
async function resolveAudioSource(
|
|
615
|
-
ctx:
|
|
635
|
+
ctx: MiokuContext,
|
|
616
636
|
options: {
|
|
617
637
|
audioText?: string;
|
|
618
638
|
config: ChatConfig;
|
|
619
|
-
|
|
639
|
+
audioService?: AudioServiceApi;
|
|
620
640
|
},
|
|
621
641
|
): Promise<string | null> {
|
|
622
642
|
const trimmed = String(options.audioText || "").trim();
|
|
@@ -650,7 +670,7 @@ export interface GroupHistoryResult {
|
|
|
650
670
|
export async function getGroupHistoryMessages(
|
|
651
671
|
groupId: number,
|
|
652
672
|
groupSessionId: string,
|
|
653
|
-
ctx:
|
|
673
|
+
ctx: MiokuContext,
|
|
654
674
|
historyCount: number,
|
|
655
675
|
db: ChatDatabase,
|
|
656
676
|
selfId: number,
|
|
@@ -689,7 +709,7 @@ export interface GroupInfoResult {
|
|
|
689
709
|
}
|
|
690
710
|
|
|
691
711
|
export async function getGroupInfoData(
|
|
692
|
-
ctx:
|
|
712
|
+
ctx: MiokuContext,
|
|
693
713
|
groupId: number,
|
|
694
714
|
selfId: number,
|
|
695
715
|
fallbackGroupName?: string,
|
|
@@ -698,9 +718,16 @@ export async function getGroupInfoData(
|
|
|
698
718
|
let memberCount: number | undefined;
|
|
699
719
|
|
|
700
720
|
try {
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
|
|
721
|
+
const bot = ctx.pickBot(selfId);
|
|
722
|
+
if (!bot) {
|
|
723
|
+
groupName = fallbackGroupName;
|
|
724
|
+
return { groupName, memberCount };
|
|
725
|
+
}
|
|
726
|
+
const groupInfo = await createGroupRef(bot, String(groupId)).getInfo();
|
|
727
|
+
if (groupInfo) {
|
|
728
|
+
groupName = groupInfo.group_name || fallbackGroupName;
|
|
729
|
+
memberCount = groupInfo.member_count;
|
|
730
|
+
}
|
|
704
731
|
} catch {
|
|
705
732
|
groupName = fallbackGroupName;
|
|
706
733
|
}
|
|
@@ -739,12 +766,14 @@ export async function getHumanizeContexts(
|
|
|
739
766
|
topicContext: topicContext || undefined,
|
|
740
767
|
expressionContext: expressionContext || undefined,
|
|
741
768
|
};
|
|
742
|
-
logger.info(
|
|
769
|
+
logger.info(
|
|
770
|
+
`[getHumanizeContexts] session=${groupSessionId} user=${userName} triggerUserId=${triggerUserId} memoryContext=undefined topicContext="${topicContext?.slice(0, 100) ?? ""}" expressionContext="${expressionContext?.slice(0, 100) ?? ""}"`,
|
|
771
|
+
);
|
|
743
772
|
return result;
|
|
744
773
|
}
|
|
745
774
|
|
|
746
775
|
export interface BuildToolContextOptions {
|
|
747
|
-
ctx:
|
|
776
|
+
ctx: MiokuContext;
|
|
748
777
|
event: any;
|
|
749
778
|
selfId: number;
|
|
750
779
|
groupSessionId: string;
|
|
@@ -761,7 +790,7 @@ export interface BuildToolContextOptions {
|
|
|
761
790
|
}
|
|
762
791
|
|
|
763
792
|
function resolveTriggerSkillRole(
|
|
764
|
-
ctx:
|
|
793
|
+
ctx: MiokuContext,
|
|
765
794
|
event: any,
|
|
766
795
|
): SkillPermissionRole {
|
|
767
796
|
const userId = event?.user_id || event?.sender?.user_id;
|
|
@@ -844,18 +873,20 @@ export function saveBotMessages(
|
|
|
844
873
|
timestamp: number,
|
|
845
874
|
config: ChatConfig,
|
|
846
875
|
db: ChatDatabase,
|
|
847
|
-
ctx:
|
|
848
|
-
|
|
876
|
+
ctx: MiokuContext,
|
|
877
|
+
bot: Bot | undefined,
|
|
878
|
+
sentMessageIds?: Array<string | undefined>,
|
|
849
879
|
): void {
|
|
850
|
-
const bot = ctx.pickBot(selfId);
|
|
851
880
|
const botNickname = config.nicknames[0] || (bot?.nickname ?? "Miku");
|
|
881
|
+
const selfId = bot ? Number(bot.bot_id) : 0;
|
|
852
882
|
|
|
853
883
|
if (!bot) {
|
|
854
884
|
ctx.logger.warn(`[saveBotMessages] bot ${selfId} not available`);
|
|
855
885
|
return;
|
|
856
886
|
}
|
|
857
887
|
|
|
858
|
-
for (
|
|
888
|
+
for (let i = 0; i < messages.length; i++) {
|
|
889
|
+
const msg = messages[i];
|
|
859
890
|
const botMsg: ChatMessage = {
|
|
860
891
|
sessionId: groupSessionId,
|
|
861
892
|
role: "assistant",
|
|
@@ -865,29 +896,27 @@ export function saveBotMessages(
|
|
|
865
896
|
userRole: "member",
|
|
866
897
|
groupId,
|
|
867
898
|
timestamp,
|
|
899
|
+
messageId: sentMessageIds?.[i],
|
|
868
900
|
};
|
|
869
901
|
db.saveMessage(botMsg);
|
|
870
902
|
}
|
|
871
903
|
}
|
|
872
904
|
|
|
873
905
|
export async function sendEmoji(
|
|
874
|
-
ctx:
|
|
906
|
+
ctx: MiokuContext,
|
|
875
907
|
groupId: number,
|
|
876
908
|
emojiPath: string | null | undefined,
|
|
877
|
-
|
|
909
|
+
bot: Bot | undefined,
|
|
878
910
|
): Promise<void> {
|
|
879
911
|
if (!emojiPath) return;
|
|
880
|
-
const bot = ctx.pickBot(selfId);
|
|
881
912
|
if (!bot) {
|
|
882
|
-
ctx.logger.error(
|
|
883
|
-
`[sendEmoji] bot ${String(selfId)} not found, skip sending emoji`,
|
|
884
|
-
);
|
|
913
|
+
ctx.logger.error(`[sendEmoji] bot not available, skip sending emoji`);
|
|
885
914
|
return;
|
|
886
915
|
}
|
|
887
916
|
|
|
888
917
|
try {
|
|
889
918
|
const emojiSegment = ctx.segment.image(`file://${emojiPath}`);
|
|
890
|
-
await bot.
|
|
919
|
+
await bot.sendMessage({ type: "group", group_id: groupId }, [emojiSegment]);
|
|
891
920
|
} catch (err) {
|
|
892
921
|
try {
|
|
893
922
|
const fsPromises = await import("fs/promises");
|
|
@@ -922,7 +951,9 @@ export async function sendEmoji(
|
|
|
922
951
|
|
|
923
952
|
const base64DataUrl = `data:${mimeType};base64,${base64}`;
|
|
924
953
|
const base64Segment = ctx.segment.image(base64DataUrl);
|
|
925
|
-
await bot.
|
|
954
|
+
await bot.sendMessage({ type: "group", group_id: groupId }, [
|
|
955
|
+
base64Segment,
|
|
956
|
+
]);
|
|
926
957
|
ctx.logger.info(`[Emoji] Sent via base64: ${path.basename(emojiPath)}`);
|
|
927
958
|
} catch (base64Err) {
|
|
928
959
|
ctx.logger.error(`[Emoji] Base64 also failed: ${base64Err}`);
|