mioku-plugin-chat 2.3.0 → 2.4.0

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,40 @@ 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 toTopicRecord(row);
33
+ }
34
+
35
+ function toExpressionRecord(row: any): ExpressionRecord {
36
+ return {
37
+ id: row.id,
38
+ sessionId: row.session_id,
39
+ userId: row.user_id,
40
+ userName: row.user_name,
41
+ situation: row.situation,
42
+ style: row.style,
43
+ example: row.example,
44
+ createdAt: row.created_at,
45
+ };
46
+ }
47
+
14
48
  /**
15
49
  * 聊天数据库接口
16
50
  */
@@ -413,40 +447,14 @@ export async function initDatabase(): Promise<ChatDatabase> {
413
447
  : (stmts.getMessages.all({ $sessionId: sessionId, $limit: limit }) as any[]);
414
448
 
415
449
  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
- }))
450
+ .map(toChatMessage)
430
451
  .reverse(); // 按时间正序
431
452
  },
432
453
 
433
454
  getBotMessages(groupId: number, limit: number = 50): ChatMessage[] {
434
455
  const rows = stmts.getBotMessages.all({ $groupId: groupId, $limit: limit }) as any[];
435
456
  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
- }))
457
+ .map(toChatMessage)
450
458
  .reverse(); // 按时间正序
451
459
  },
452
460
 
@@ -458,20 +466,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
458
466
  { $groupId: groupId, $limit: limit },
459
467
  ) as any[];
460
468
  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
- }))
469
+ .map(toChatMessage)
475
470
  .reverse();
476
471
  },
477
472
 
@@ -489,20 +484,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
489
484
  : (stmts.getMessagesByUser.all({ $userId: userId, $limit: limit }) as any[]);
490
485
 
491
486
  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
- }))
487
+ .map(toChatMessage)
506
488
  .reverse();
507
489
  },
508
490
 
@@ -512,20 +494,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
512
494
  : (stmts.getAllMessagesByUser.all({ $userId: userId }) as any[]);
513
495
 
514
496
  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
- }))
497
+ .map(toChatMessage)
529
498
  .reverse();
530
499
  },
531
500
 
@@ -539,20 +508,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
539
508
  $startTimestamp: startTimestamp,
540
509
  $endTimestamp: endTimestamp,
541
510
  }) 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
- }));
511
+ return rows.map(toChatMessage);
556
512
  },
557
513
 
558
514
  updateCompressedContext(sessionId: string, context: string): void {
@@ -579,20 +535,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
579
535
  $limit: limit,
580
536
  }) as any[];
581
537
  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
- }))
538
+ .map(toChatMessage)
596
539
  .reverse();
597
540
  },
598
541
 
@@ -613,18 +556,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
613
556
 
614
557
  getTopics(sessionId: string, limit: number = 10): TopicRecord[] {
615
558
  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
- }));
559
+ return rows.map(toTopicRecord);
628
560
  },
629
561
 
630
562
  getTopicByWindow(
@@ -638,18 +570,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
638
570
  $windowEndAt: windowEndAt,
639
571
  }) as any;
640
572
  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
- };
573
+ return toTopicRecord(row);
653
574
  },
654
575
 
655
576
  updateTopic(
@@ -686,16 +607,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
686
607
 
687
608
  getExpressions(sessionId: string, limit: number = 50): ExpressionRecord[] {
688
609
  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
- }));
610
+ return rows.map(toExpressionRecord);
699
611
  },
700
612
 
701
613
  getExpressionsByUser(
@@ -703,16 +615,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
703
615
  limit: number = 50,
704
616
  ): ExpressionRecord[] {
705
617
  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
- }));
618
+ return rows.map(toExpressionRecord);
716
619
  },
717
620
 
718
621
  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
+ }