mioku-plugin-chat 2.3.1 → 2.4.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/db.ts CHANGED
@@ -11,6 +11,51 @@ import type {
11
11
  MediaSummaryRecord,
12
12
  } from "./types";
13
13
 
14
+ function toChatMessage(row: any): ChatMessage {
15
+ return {
16
+ id: row.id,
17
+ sessionId: row.session_id,
18
+ role: row.role,
19
+ content: row.content,
20
+ userId: row.user_id,
21
+ userName: row.user_name,
22
+ userRole: row.user_role,
23
+ userTitle: row.user_title,
24
+ groupId: row.group_id,
25
+ groupName: row.group_name,
26
+ timestamp: row.timestamp,
27
+ messageId: row.message_id,
28
+ };
29
+ }
30
+
31
+ function toTopicRecord(row: any): TopicRecord {
32
+ return {
33
+ id: row.id,
34
+ sessionId: row.session_id,
35
+ title: row.title,
36
+ keywords: row.keywords,
37
+ summary: row.summary,
38
+ messageCount: row.message_count,
39
+ windowStartAt: row.window_start_at ?? undefined,
40
+ windowEndAt: row.window_end_at ?? undefined,
41
+ createdAt: row.created_at,
42
+ updatedAt: row.updated_at,
43
+ };
44
+ }
45
+
46
+ function toExpressionRecord(row: any): ExpressionRecord {
47
+ return {
48
+ id: row.id,
49
+ sessionId: row.session_id,
50
+ userId: row.user_id,
51
+ userName: row.user_name,
52
+ situation: row.situation,
53
+ style: row.style,
54
+ example: row.example,
55
+ createdAt: row.created_at,
56
+ };
57
+ }
58
+
14
59
  /**
15
60
  * 聊天数据库接口
16
61
  */
@@ -413,40 +458,14 @@ export async function initDatabase(): Promise<ChatDatabase> {
413
458
  : (stmts.getMessages.all({ $sessionId: sessionId, $limit: limit }) as any[]);
414
459
 
415
460
  return rows
416
- .map((row) => ({
417
- id: row.id,
418
- sessionId: row.session_id,
419
- role: row.role,
420
- content: row.content,
421
- userId: row.user_id,
422
- userName: row.user_name,
423
- userRole: row.user_role,
424
- userTitle: row.user_title,
425
- groupId: row.group_id,
426
- groupName: row.group_name,
427
- timestamp: row.timestamp,
428
- messageId: row.message_id,
429
- }))
461
+ .map(toChatMessage)
430
462
  .reverse(); // 按时间正序
431
463
  },
432
464
 
433
465
  getBotMessages(groupId: number, limit: number = 50): ChatMessage[] {
434
466
  const rows = stmts.getBotMessages.all({ $groupId: groupId, $limit: limit }) as any[];
435
467
  return rows
436
- .map((row) => ({
437
- id: row.id,
438
- sessionId: row.session_id,
439
- role: row.role,
440
- content: row.content,
441
- userId: row.user_id,
442
- userName: row.user_name,
443
- userRole: row.user_role,
444
- userTitle: row.user_title,
445
- groupId: row.group_id,
446
- groupName: row.group_name,
447
- timestamp: row.timestamp,
448
- messageId: row.message_id,
449
- }))
468
+ .map(toChatMessage)
450
469
  .reverse(); // 按时间正序
451
470
  },
452
471
 
@@ -458,20 +477,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
458
477
  { $groupId: groupId, $limit: limit },
459
478
  ) as any[];
460
479
  return rows
461
- .map((row) => ({
462
- id: row.id,
463
- sessionId: row.session_id,
464
- role: row.role,
465
- content: row.content,
466
- userId: row.user_id,
467
- userName: row.user_name,
468
- userRole: row.user_role,
469
- userTitle: row.user_title,
470
- groupId: row.group_id,
471
- groupName: row.group_name,
472
- timestamp: row.timestamp,
473
- messageId: row.message_id,
474
- }))
480
+ .map(toChatMessage)
475
481
  .reverse();
476
482
  },
477
483
 
@@ -489,20 +495,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
489
495
  : (stmts.getMessagesByUser.all({ $userId: userId, $limit: limit }) as any[]);
490
496
 
491
497
  return rows
492
- .map((row) => ({
493
- id: row.id,
494
- sessionId: row.session_id,
495
- role: row.role,
496
- content: row.content,
497
- userId: row.user_id,
498
- userName: row.user_name,
499
- userRole: row.user_role,
500
- userTitle: row.user_title,
501
- groupId: row.group_id,
502
- groupName: row.group_name,
503
- timestamp: row.timestamp,
504
- messageId: row.message_id,
505
- }))
498
+ .map(toChatMessage)
506
499
  .reverse();
507
500
  },
508
501
 
@@ -512,20 +505,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
512
505
  : (stmts.getAllMessagesByUser.all({ $userId: userId }) as any[]);
513
506
 
514
507
  return rows
515
- .map((row) => ({
516
- id: row.id,
517
- sessionId: row.session_id,
518
- role: row.role,
519
- content: row.content,
520
- userId: row.user_id,
521
- userName: row.user_name,
522
- userRole: row.user_role,
523
- userTitle: row.user_title,
524
- groupId: row.group_id,
525
- groupName: row.group_name,
526
- timestamp: row.timestamp,
527
- messageId: row.message_id,
528
- }))
508
+ .map(toChatMessage)
529
509
  .reverse();
530
510
  },
531
511
 
@@ -539,20 +519,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
539
519
  $startTimestamp: startTimestamp,
540
520
  $endTimestamp: endTimestamp,
541
521
  }) as any[];
542
- return rows.map((row) => ({
543
- id: row.id,
544
- sessionId: row.session_id,
545
- role: row.role,
546
- content: row.content,
547
- userId: row.user_id,
548
- userName: row.user_name,
549
- userRole: row.user_role,
550
- userTitle: row.user_title,
551
- groupId: row.group_id,
552
- groupName: row.group_name,
553
- timestamp: row.timestamp,
554
- messageId: row.message_id,
555
- }));
522
+ return rows.map(toChatMessage);
556
523
  },
557
524
 
558
525
  updateCompressedContext(sessionId: string, context: string): void {
@@ -579,20 +546,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
579
546
  $limit: limit,
580
547
  }) as any[];
581
548
  return rows
582
- .map((row) => ({
583
- id: row.id,
584
- sessionId: row.session_id,
585
- role: row.role,
586
- content: row.content,
587
- userId: row.user_id,
588
- userName: row.user_name,
589
- userRole: row.user_role,
590
- userTitle: row.user_title,
591
- groupId: row.group_id,
592
- groupName: row.group_name,
593
- timestamp: row.timestamp,
594
- messageId: row.message_id,
595
- }))
549
+ .map(toChatMessage)
596
550
  .reverse();
597
551
  },
598
552
 
@@ -613,18 +567,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
613
567
 
614
568
  getTopics(sessionId: string, limit: number = 10): TopicRecord[] {
615
569
  const rows = stmts.getTopics.all({ $sessionId: sessionId, $limit: limit }) as any[];
616
- return rows.map((row) => ({
617
- id: row.id,
618
- sessionId: row.session_id,
619
- title: row.title,
620
- keywords: row.keywords,
621
- summary: row.summary,
622
- messageCount: row.message_count,
623
- windowStartAt: row.window_start_at ?? undefined,
624
- windowEndAt: row.window_end_at ?? undefined,
625
- createdAt: row.created_at,
626
- updatedAt: row.updated_at,
627
- }));
570
+ return rows.map(toTopicRecord);
628
571
  },
629
572
 
630
573
  getTopicByWindow(
@@ -638,18 +581,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
638
581
  $windowEndAt: windowEndAt,
639
582
  }) as any;
640
583
  if (!row) return null;
641
- return {
642
- id: row.id,
643
- sessionId: row.session_id,
644
- title: row.title,
645
- keywords: row.keywords,
646
- summary: row.summary,
647
- messageCount: row.message_count,
648
- windowStartAt: row.window_start_at ?? undefined,
649
- windowEndAt: row.window_end_at ?? undefined,
650
- createdAt: row.created_at,
651
- updatedAt: row.updated_at,
652
- };
584
+ return toTopicRecord(row);
653
585
  },
654
586
 
655
587
  updateTopic(
@@ -686,16 +618,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
686
618
 
687
619
  getExpressions(sessionId: string, limit: number = 50): ExpressionRecord[] {
688
620
  const rows = stmts.getExpressions.all({ $sessionId: sessionId, $limit: limit }) as any[];
689
- return rows.map((row) => ({
690
- id: row.id,
691
- sessionId: row.session_id,
692
- userId: row.user_id,
693
- userName: row.user_name,
694
- situation: row.situation,
695
- style: row.style,
696
- example: row.example,
697
- createdAt: row.created_at,
698
- }));
621
+ return rows.map(toExpressionRecord);
699
622
  },
700
623
 
701
624
  getExpressionsByUser(
@@ -703,16 +626,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
703
626
  limit: number = 50,
704
627
  ): ExpressionRecord[] {
705
628
  const rows = stmts.getExpressionsByUser.all({ $userId: userId, $limit: limit }) as any[];
706
- return rows.map((row) => ({
707
- id: row.id,
708
- sessionId: row.session_id,
709
- userId: row.user_id,
710
- userName: row.user_name,
711
- situation: row.situation,
712
- style: row.style,
713
- example: row.example,
714
- createdAt: row.created_at,
715
- }));
629
+ return rows.map(toExpressionRecord);
716
630
  },
717
631
 
718
632
  replaceExpressionsByUser(
@@ -0,0 +1,135 @@
1
+ import type { MiokiContext } from "mioki";
2
+ import type { AIService } from "mioku";
3
+ import type { ChatPluginContext } from "../context";
4
+ import type { ChatConfig, TargetMessage } from "../types";
5
+ import { getBotRole } from "../utils";
6
+ import { buildStructuredUserInputFromTarget } from "../manage/group-structured-history";
7
+
8
+ export async function handleIdleCheckDebug(
9
+ pluginCtx: ChatPluginContext,
10
+ e: any,
11
+ cfg: ChatConfig,
12
+ ): Promise<void> {
13
+ const ctx: MiokiContext = pluginCtx.ctx;
14
+ const isOwner = ctx.isOwner?.(e) ?? false;
15
+ if (!isOwner) {
16
+ await e.reply("只有主人才能使用这个指令~");
17
+ return;
18
+ }
19
+ const groupIdStr = e.message[0]?.text?.replace("/空闲检查", "")?.trim() || "";
20
+ const targetGroupId = parseInt(groupIdStr, 10);
21
+ if (!targetGroupId) {
22
+ await e.reply("请指定群号,如:/空闲检查 123456");
23
+ return;
24
+ }
25
+
26
+ const groupSessionId = `group:${targetGroupId}`;
27
+ try {
28
+ const now = Date.now();
29
+ const botNickname =
30
+ cfg.nicknames[0] || ctx.pickBot(e.self_id).nickname || "Bot";
31
+ ctx.logger.info(`[Debug] Manual idle check: group ${targetGroupId}`);
32
+
33
+ const { history } = await pluginCtx.getGroupHistoryMessages(
34
+ targetGroupId,
35
+ groupSessionId,
36
+ ctx,
37
+ cfg.historyCount,
38
+ pluginCtx.db,
39
+ e.self_id,
40
+ pluginCtx.buildHistoryMediaOptions(pluginCtx.aiInstance, cfg),
41
+ );
42
+ const planResult = await pluginCtx.humanize.actionPlanner.plan(
43
+ groupSessionId,
44
+ botNickname,
45
+ history,
46
+ "[Check if you want to answer the call]",
47
+ true,
48
+ );
49
+
50
+ if (planResult.action !== "reply") {
51
+ await e.reply(
52
+ `[空闲检测] 群 ${targetGroupId}\n决定: ${planResult.action}\n原因: ${planResult.reason}`,
53
+ );
54
+ return;
55
+ }
56
+
57
+ const targetMessage: TargetMessage = {
58
+ userName: "系统",
59
+ userId: 0,
60
+ userRole: "member",
61
+ content: "[No one in the group is talking? I'll answer!]",
62
+ messageId: 0,
63
+ timestamp: now,
64
+ };
65
+ const botRole = await getBotRole(targetGroupId, ctx, e.self_id);
66
+ const toolCtx = pluginCtx.buildToolContext({
67
+ ctx,
68
+ event: null,
69
+ groupSessionId,
70
+ groupId: targetGroupId,
71
+ userId: 0,
72
+ config: cfg,
73
+ aiService: ctx.services!.ai as AIService,
74
+ db: pluginCtx.db,
75
+ botRole,
76
+ humanize: pluginCtx.humanize,
77
+ targetMessage,
78
+ selfId: e.self_id,
79
+ });
80
+
81
+ const result = await pluginCtx.runWithRateLimitGuard(
82
+ () =>
83
+ pluginCtx.runChat(
84
+ pluginCtx.aiInstance,
85
+ toolCtx,
86
+ history,
87
+ targetMessage,
88
+ {
89
+ config: cfg,
90
+ botNickname,
91
+ botRole: toolCtx.botRole,
92
+ aiService: ctx.services!.ai as AIService,
93
+ isGroup: true,
94
+ plannerThoughts: `You stumbled upon some message in this group and decided to reply.\nQuote messages from group friends appropriately (using [reply:message ID] format).\nDon't mention your intentions like "I'm here to answer".`,
95
+ replyContext: { type: "idle" },
96
+ },
97
+ pluginCtx.humanize,
98
+ pluginCtx.skillManager,
99
+ ),
100
+ { groupId: targetGroupId, label: "idle-check" },
101
+ );
102
+ if (!result) {
103
+ await e.reply(`[空闲检测] 群 ${targetGroupId} 因限流被跳过`);
104
+ return;
105
+ }
106
+
107
+ await pluginCtx.sendAIResponse(
108
+ {
109
+ ctx,
110
+ groupId: targetGroupId,
111
+ messages: result.messages,
112
+ config: cfg,
113
+ sentIndices: toolCtx.sentMessageIndices,
114
+ },
115
+ e.self_id,
116
+ );
117
+ const now2 = Date.now();
118
+ pluginCtx.saveBotMessages(
119
+ targetGroupId,
120
+ groupSessionId,
121
+ result.messages,
122
+ now2,
123
+ cfg,
124
+ pluginCtx.db,
125
+ ctx,
126
+ e.self_id,
127
+ );
128
+ await e.reply(
129
+ `[空闲检测] 群 ${targetGroupId} 已发送回复: ${planResult.reason}`,
130
+ );
131
+ } catch (err) {
132
+ ctx.logger.error(`[Debug] Idle check failed: ${err}`);
133
+ await e.reply(`[空闲检测] 失败: ${err}`);
134
+ }
135
+ }