mioku-plugin-chat 3.0.6 → 3.1.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/context.ts CHANGED
@@ -38,7 +38,7 @@ export interface ChatPluginContext {
38
38
  ctx: MiokuContext;
39
39
  defaultConfig: ChatConfig;
40
40
  configProvider: ChatConfigProvider;
41
- getConfig: (groupId?: number) => Promise<ChatConfig>;
41
+ getConfig: (groupId?: string) => Promise<ChatConfig>;
42
42
  db: ChatDatabase;
43
43
  aiInstance: AIInstance;
44
44
  workAIInstance: AIInstance;
@@ -75,8 +75,8 @@ export interface ChatPluginContext {
75
75
  runChat: RunChat;
76
76
  startCooldownTimer: (
77
77
  groupSessionId: string,
78
- groupId: number,
79
- selfId: number,
78
+ groupId: string,
79
+ selfId: string,
80
80
  ) => void;
81
81
  recordGroupMessageForLearning: (
82
82
  userMsg: ChatMessage,
@@ -91,12 +91,12 @@ export interface ChatRuntimeState {
91
91
  }
92
92
 
93
93
  export interface ChatHandlerState {
94
- getConfig: (groupId?: number) => Promise<ChatConfig>;
94
+ getConfig: (groupId?: string) => Promise<ChatConfig>;
95
95
  matchMessageCommands?: (
96
96
  text: string,
97
97
  ) => Array<{ plugin: string; command: string }>;
98
98
  runtimeState: ChatRuntimeState;
99
- pokeCooldowns: Map<number, number>;
99
+ pokeCooldowns: Map<string, number>;
100
100
  }
101
101
 
102
102
  export interface ChatRuntime {
package/core/base.ts CHANGED
@@ -25,7 +25,7 @@ import {
25
25
 
26
26
  export interface SendAIResponseOptions {
27
27
  ctx: MiokuContext;
28
- groupId: number;
28
+ groupId: string;
29
29
  messages: string[];
30
30
  config: ChatConfig;
31
31
  sentIndices?: Set<number>;
@@ -78,7 +78,7 @@ async function waitTypingDelay(
78
78
 
79
79
  export async function sendAIResponse(
80
80
  options: SendAIResponseOptions,
81
- selfId: number,
81
+ selfId: string,
82
82
  ): Promise<Array<string | undefined>> {
83
83
  const {
84
84
  ctx,
@@ -252,11 +252,11 @@ export async function sendAIResponse(
252
252
 
253
253
  export async function sendMessage(
254
254
  ctx: MiokuContext,
255
- groupId: number | undefined,
256
- userId: number,
255
+ groupId: string | undefined,
256
+ userId: string,
257
257
  text: string,
258
258
  config: ChatConfig,
259
- selfId: number,
259
+ selfId: string,
260
260
  audioService?: AudioServiceApi,
261
261
  ): Promise<void> {
262
262
  const typingDelayEnabled = config.enableTypingDelay ?? false;
@@ -555,8 +555,8 @@ async function buildMarkdownImage(
555
555
 
556
556
  async function dispatchSegments(
557
557
  bot: any,
558
- groupId: number | undefined,
559
- userId: number | undefined,
558
+ groupId: string | undefined,
559
+ userId: string | undefined,
560
560
  buildSegments: (imageSource?: string) => any[],
561
561
  fallbackImagePath?: string,
562
562
  ): Promise<string | undefined> {
@@ -583,8 +583,8 @@ async function dispatchSegments(
583
583
 
584
584
  async function sendByTarget(
585
585
  bot: Bot,
586
- groupId: number | undefined,
587
- userId: number | undefined,
586
+ groupId: string | undefined,
587
+ userId: string | undefined,
588
588
  segments: readonly any[],
589
589
  ): Promise<import("mioku").SentMessage | undefined> {
590
590
  if (groupId) {
@@ -668,12 +668,12 @@ export interface GroupHistoryResult {
668
668
  }
669
669
 
670
670
  export async function getGroupHistoryMessages(
671
- groupId: number,
671
+ groupId: string,
672
672
  groupSessionId: string,
673
673
  ctx: MiokuContext,
674
674
  historyCount: number,
675
675
  db: ChatDatabase,
676
- selfId: number,
676
+ selfId: string,
677
677
  mediaOptions?: {
678
678
  ai?: AIInstance;
679
679
  workingModel?: string;
@@ -710,8 +710,8 @@ export interface GroupInfoResult {
710
710
 
711
711
  export async function getGroupInfoData(
712
712
  ctx: MiokuContext,
713
- groupId: number,
714
- selfId: number,
713
+ groupId: string,
714
+ selfId: string,
715
715
  fallbackGroupName?: string,
716
716
  ): Promise<GroupInfoResult> {
717
717
  let groupName: string | undefined;
@@ -746,7 +746,7 @@ export async function getHumanizeContexts(
746
746
  groupSessionId: string,
747
747
  userName: string,
748
748
  history: ChatMessage[],
749
- triggerUserId?: number,
749
+ triggerUserId?: string,
750
750
  ): Promise<HumanizeContextsResult> {
751
751
  const historyStartAt = history.length > 0 ? history[0].timestamp : undefined;
752
752
 
@@ -775,10 +775,10 @@ export async function getHumanizeContexts(
775
775
  export interface BuildToolContextOptions {
776
776
  ctx: MiokuContext;
777
777
  event: any;
778
- selfId: number;
778
+ selfId: string;
779
779
  groupSessionId: string;
780
- groupId?: number;
781
- userId: number;
780
+ groupId?: string;
781
+ userId: string;
782
782
  config: ChatConfig;
783
783
  aiService: AIService;
784
784
  db: ChatDatabase;
@@ -867,7 +867,7 @@ export function buildToolContext(
867
867
  }
868
868
 
869
869
  export function saveBotMessages(
870
- groupId: number,
870
+ groupId: string,
871
871
  groupSessionId: string,
872
872
  messages: string[],
873
873
  timestamp: number,
@@ -891,7 +891,7 @@ export function saveBotMessages(
891
891
  sessionId: groupSessionId,
892
892
  role: "assistant",
893
893
  content: msg ?? "",
894
- userId: selfId ?? 0,
894
+ userId: String(selfId ?? ""),
895
895
  userName: botNickname ?? "Miku",
896
896
  userRole: "member",
897
897
  groupId,
@@ -904,7 +904,7 @@ export function saveBotMessages(
904
904
 
905
905
  export async function sendEmoji(
906
906
  ctx: MiokuContext,
907
- groupId: number,
907
+ groupId: string,
908
908
  emojiPath: string | null | undefined,
909
909
  bot: Bot | undefined,
910
910
  ): Promise<void> {
@@ -142,7 +142,7 @@ export async function runChat(
142
142
  const usageContext = {
143
143
  usageId,
144
144
  source: "chat",
145
- botId: getEventNumber(toolCtx.event, "self_id"),
145
+ botId: getEventId(toolCtx.event, "self_id"),
146
146
  groupId: toolCtx.groupId,
147
147
  groupName: getEventString(toolCtx.event, "group_name"),
148
148
  userId: toolCtx.userId,
@@ -960,7 +960,7 @@ ${failedSummary}
960
960
  ],
961
961
  usageContext: {
962
962
  source: "chat.tool-failure",
963
- botId: getEventNumber(toolCtx.event, "self_id"),
963
+ botId: getEventId(toolCtx.event, "self_id"),
964
964
  groupId: toolCtx.groupId,
965
965
  groupName: getEventString(toolCtx.event, "group_name"),
966
966
  userId: toolCtx.userId,
@@ -984,12 +984,12 @@ ${failedSummary}
984
984
  return "我刚刚查这条信息时出了点问题,你可以换个关键词再试试,或者给我更具体一点的线索。";
985
985
  }
986
986
 
987
- function getEventNumber(event: unknown, key: string): number | undefined {
987
+ function getEventId(event: unknown, key: string): string | undefined {
988
988
  if (!event || typeof event !== "object") return undefined;
989
989
  const value = (event as Record<string, unknown>)[key];
990
- return typeof value === "number" && Number.isFinite(value)
991
- ? value
992
- : undefined;
990
+ if (value == null) return undefined;
991
+ const text = String(value).trim();
992
+ return text.length > 0 ? text : undefined;
993
993
  }
994
994
 
995
995
  function getEventString(event: unknown, key: string): string | undefined {
package/core/chat-turn.ts CHANGED
@@ -14,9 +14,9 @@ export type RuntimeReplyContextType =
14
14
 
15
15
  export interface ExecuteChatRuntimeRequestOptions {
16
16
  event?: any;
17
- selfId?: number;
18
- groupId?: number;
19
- userId?: number;
17
+ selfId?: string;
18
+ groupId?: string;
19
+ userId?: string;
20
20
  config: ChatConfig;
21
21
  targetMessageContent?: string;
22
22
  promptInjections?: ChatRuntimePromptInjection[];
@@ -28,9 +28,9 @@ export interface ExecuteChatRuntimeRequestOptions {
28
28
  interface ResolvedRuntimeContext {
29
29
  event: any;
30
30
  isGroup: boolean;
31
- groupId?: number;
32
- userId: number;
33
- selfId: number;
31
+ groupId?: string;
32
+ userId: string;
33
+ selfId: string;
34
34
  sessionId: string;
35
35
  personalSessionId?: string;
36
36
  senderName: string;
@@ -61,8 +61,12 @@ function resolveRuntimeContext(
61
61
  if (options.event) {
62
62
  const event = options.event;
63
63
  const isGroup = event.message_type === "group";
64
- const groupId: number | undefined = isGroup ? event.group_id : undefined;
65
- const userId: number = event.user_id || event.sender?.user_id || 0;
64
+ const groupId: string | undefined = isGroup
65
+ ? String(event.group_id ?? "").trim() || undefined
66
+ : undefined;
67
+ const userId: string = String(
68
+ event.user_id ?? event.sender?.user_id ?? "",
69
+ ).trim();
66
70
  return {
67
71
  event,
68
72
  isGroup,
@@ -80,18 +84,18 @@ function resolveRuntimeContext(
80
84
  };
81
85
  }
82
86
 
83
- if (typeof options.selfId !== "number") {
87
+ const selfId = String(options.selfId ?? "").trim();
88
+ if (!selfId) {
84
89
  throw new Error("Chat runtime requires either event or selfId");
85
90
  }
86
- if (
87
- typeof options.groupId !== "number" &&
88
- typeof options.userId !== "number"
89
- ) {
91
+ const optionGroupId = String(options.groupId ?? "").trim() || undefined;
92
+ const optionUserId = String(options.userId ?? "").trim();
93
+ if (!optionGroupId && !optionUserId) {
90
94
  throw new Error("Chat runtime requires groupId or userId");
91
95
  }
92
96
 
93
- const isGroup = typeof options.groupId === "number";
94
- const userId = options.userId ?? 0;
97
+ const isGroup = Boolean(optionGroupId);
98
+ const userId = optionUserId;
95
99
  const event = {
96
100
  self_id: options.selfId,
97
101
  message_type: isGroup ? "group" : "private",
@@ -110,15 +114,15 @@ function resolveRuntimeContext(
110
114
  return {
111
115
  event,
112
116
  isGroup,
113
- groupId: options.groupId,
117
+ groupId: optionGroupId,
114
118
  userId,
115
- selfId: options.selfId,
116
- sessionId: options.groupId
117
- ? `group:${options.groupId}`
119
+ selfId,
120
+ sessionId: optionGroupId
121
+ ? `group:${optionGroupId}`
118
122
  : `personal:${userId}`,
119
123
  personalSessionId:
120
- options.groupId && userId ? `personal:${userId}` : undefined,
121
- senderName: options.groupId ? "system" : String(userId),
124
+ optionGroupId && userId ? `personal:${userId}` : undefined,
125
+ senderName: optionGroupId ? "system" : String(userId),
122
126
  userRole: "member",
123
127
  userTitle: undefined,
124
128
  groupName: undefined,
@@ -133,10 +137,10 @@ export async function finalizeChatTurn(
133
137
  event: any;
134
138
  cfg: ChatConfig;
135
139
  result: { messages: string[]; emojiPath?: string | null };
136
- groupId?: number;
140
+ groupId?: string;
137
141
  groupSessionId: string;
138
- userId: number;
139
- selfId: number;
142
+ userId: string;
143
+ selfId: string;
140
144
  toolCtx: { sentMessageIndices?: Set<number> };
141
145
  send: boolean;
142
146
  isLive: boolean;
@@ -247,8 +251,8 @@ export async function processChat(
247
251
  ): Promise<void> {
248
252
  const { ctx } = pluginCtx;
249
253
  const isGroup = e.message_type === "group";
250
- const groupId: number | undefined = isGroup ? e.group_id : undefined;
251
- const userId: number = e.user_id || e.sender?.user_id;
254
+ const groupId: string | undefined = isGroup ? e.group_id : undefined;
255
+ const userId: string = e.user_id || e.sender?.user_id;
252
256
  const selfId = options.replyBot ? Number(options.replyBot.bot_id) : e.self_id;
253
257
  const cfg = await pluginCtx.getConfig(groupId);
254
258
 
@@ -70,12 +70,12 @@ export interface HistoryMediaProcessingOptions {
70
70
  error(message: string): void;
71
71
  };
72
72
  bot?: Bot;
73
- groupId?: number;
73
+ groupId?: string;
74
74
  runAIRequest?<T>(request: () => Promise<T>): Promise<T | null>;
75
75
  }
76
76
 
77
77
  export interface GroupNoticeHistorySummary {
78
- userId: number;
78
+ userId: string;
79
79
  userName: string;
80
80
  userRole: string;
81
81
  content: string;
@@ -701,18 +701,18 @@ function extractNoticeText(notice: any): string {
701
701
  }
702
702
 
703
703
  function extractNoticeSender(notice: any): {
704
- userId: number;
704
+ userId: string;
705
705
  userName: string;
706
706
  } {
707
- const userId = Number(
708
- notice?.user_id ||
709
- notice?.sender_id ||
710
- notice?.operator_id ||
711
- notice?.poster_id ||
712
- notice?.publisher_id ||
713
- notice?.sender?.user_id ||
714
- 0,
715
- );
707
+ const userId = String(
708
+ notice?.user_id ??
709
+ notice?.sender_id ??
710
+ notice?.operator_id ??
711
+ notice?.poster_id ??
712
+ notice?.publisher_id ??
713
+ notice?.sender?.user_id ??
714
+ "",
715
+ ).trim();
716
716
  const userName =
717
717
  notice?.sender?.card ||
718
718
  notice?.sender?.nickname ||
@@ -722,7 +722,7 @@ function extractNoticeSender(notice: any): {
722
722
  notice?.operator_name ||
723
723
  (userId ? String(userId) : "unknown");
724
724
  return {
725
- userId: Number.isFinite(userId) ? userId : 0,
725
+ userId,
726
726
  userName: String(userName),
727
727
  };
728
728
  }
@@ -28,7 +28,7 @@ export function buildHistoryMediaProcessingOptions(
28
28
  saveMediaSummary(summary: MediaSummaryRecord): void;
29
29
  },
30
30
  bot: Bot,
31
- groupId: number,
31
+ groupId: string,
32
32
  log: HistoryMediaProcessingOptions["logger"],
33
33
  runAIRequest?: <T>(request: () => Promise<T>) => Promise<T | null>,
34
34
  ): HistoryMediaProcessingOptions {
@@ -81,7 +81,7 @@ export function getCardData(seg: unknown): string | null {
81
81
 
82
82
  export function isMediaAnalysisBlocked(
83
83
  config: ChatConfig,
84
- userId: number,
84
+ userId: string,
85
85
  ): boolean {
86
86
  return Boolean(config.mediaAnalysisBlacklistUsers?.includes(userId));
87
87
  }
package/core/prompt.ts CHANGED
@@ -274,7 +274,7 @@ function buildResponseFormatSection(
274
274
  - For action markers like [] , put them on their own line when they are meant to be a separate action.
275
275
 
276
276
  - **SPECIAL ACTIONS in your text (auto-parsed and removed from message):**
277
- - Use [at:123456] in your text to @ someone (123456 is the QQ number)
277
+ - Use [at:<user_id>] in your text to @ someone (<user_id> is the platform user id shown in history)
278
278
  - Use [poke:123456] in your text to poke someone. IMPORTANT: when you plan to poke a user, DON't describe your poke actions.
279
279
  - Use [reply:message_id] at the START of a line to quote-reply that message (copy the message_id EXACTLY as shown after # in the chat history; it may contain letters, e.g. [reply:P2rW...pMB])
280
280
  - **You can use MULTIPLE [reply:xxx] markers in different lines to quote multiple messages!**`);
@@ -67,7 +67,11 @@ export function createInfoTools(toolCtx: ToolContext): AITool[] {
67
67
  parameters: {
68
68
  type: "object",
69
69
  properties: {
70
- user_id: { type: "number", description: "QQ number of the member" },
70
+ user_id: {
71
+ type: "string",
72
+ description:
73
+ "Platform user id of the member (QQ number, or openid on QQ official)",
74
+ },
71
75
  },
72
76
  required: ["user_id"],
73
77
  },
@@ -137,7 +141,7 @@ export function createInfoTools(toolCtx: ToolContext): AITool[] {
137
141
  type: "object",
138
142
  properties: {
139
143
  message_id: {
140
- type: "number",
144
+ type: "string",
141
145
  description:
142
146
  "The message ID (message_id) of the image or video. You can get this from the original message that contains the media.",
143
147
  },
@@ -250,8 +254,9 @@ export function createInfoTools(toolCtx: ToolContext): AITool[] {
250
254
  type: "object",
251
255
  properties: {
252
256
  user_id: {
253
- type: "number",
254
- description: "QQ number of the member whose avatar you want to view",
257
+ type: "string",
258
+ description:
259
+ "Platform user id of the member whose avatar you want to view",
255
260
  },
256
261
  },
257
262
  required: ["user_id"],
package/core/tools/web.ts CHANGED
@@ -23,14 +23,11 @@ function resolveUserHistoryLimit(value: unknown): number {
23
23
 
24
24
  function extractTargetUserIdsFromQuestion(
25
25
  question: string,
26
- requesterUserId: number,
27
- ): number[] {
26
+ requesterUserId: string,
27
+ ): string[] {
28
28
  const matches = question.match(/\b\d{5,12}\b/g) || [];
29
- const parsed = matches
30
- .map((item) => Number(item))
31
- .filter((item) => Number.isFinite(item) && item > 0);
32
- const ids = [requesterUserId, ...parsed].filter(
33
- (item) => Number.isFinite(item) && item > 0,
29
+ const ids = [String(requesterUserId ?? "").trim(), ...matches].filter(
30
+ (item) => item.length > 0,
34
31
  );
35
32
  return [...new Set(ids)].slice(0, 3);
36
33
  }
@@ -138,8 +135,8 @@ async function fetchGroupHistoryByMessageIdPaging(
138
135
  sessionId: toolCtx.sessionId,
139
136
  role: String(raw.user_id) === String(bot.bot_id) ? "assistant" : "user",
140
137
  content,
141
- userId: Number(raw.user_id || 0),
142
- userName: raw.nickname || String(raw.user_id || "unknown"),
138
+ userId: String(raw.user_id ?? "").trim(),
139
+ userName: raw.nickname || String(raw.user_id ?? "unknown"),
143
140
  userRole: "member",
144
141
  groupId: toolCtx.groupId,
145
142
  timestamp: ts,
package/db.ts CHANGED
@@ -69,14 +69,14 @@ export interface ChatDatabase {
69
69
  before?: number,
70
70
  ): ChatMessage[];
71
71
  // 获取 bot 发送的消息
72
- getBotMessages(groupId: number, limit?: number): ChatMessage[];
73
- getStoredGroupNoticeMessages(groupId: number, limit?: number): ChatMessage[];
72
+ getBotMessages(groupId: string, limit?: number): ChatMessage[];
73
+ getStoredGroupNoticeMessages(groupId: string, limit?: number): ChatMessage[];
74
74
  getMessagesByUser(
75
- userId: number,
75
+ userId: string,
76
76
  sessionId?: string,
77
77
  limit?: number,
78
78
  ): ChatMessage[];
79
- getAllMessagesByUser(userId: number, sessionId?: string): ChatMessage[];
79
+ getAllMessagesByUser(userId: string, sessionId?: string): ChatMessage[];
80
80
  getMessagesByTimeRange(
81
81
  sessionId: string,
82
82
  startTimestamp: number,
@@ -108,9 +108,9 @@ export interface ChatDatabase {
108
108
  // 表达学习
109
109
  saveExpression(expr: ExpressionRecord): void;
110
110
  getExpressions(sessionId: string, limit?: number): ExpressionRecord[];
111
- getExpressionsByUser(userId: number, limit?: number): ExpressionRecord[];
111
+ getExpressionsByUser(userId: string, limit?: number): ExpressionRecord[];
112
112
  replaceExpressionsByUser(
113
- userId: number,
113
+ userId: string,
114
114
  userName: string,
115
115
  expressions: Array<
116
116
  Pick<ExpressionRecord, "situation" | "style" | "example">
@@ -473,7 +473,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
473
473
  .reverse(); // 按时间正序
474
474
  },
475
475
 
476
- getBotMessages(groupId: number, limit: number = 50): ChatMessage[] {
476
+ getBotMessages(groupId: string, limit: number = 50): ChatMessage[] {
477
477
  const rows = stmts.getBotMessages.all({ $groupId: groupId, $limit: limit }) as any[];
478
478
  return rows
479
479
  .map(toChatMessage)
@@ -481,7 +481,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
481
481
  },
482
482
 
483
483
  getStoredGroupNoticeMessages(
484
- groupId: number,
484
+ groupId: string,
485
485
  limit: number = 20,
486
486
  ): ChatMessage[] {
487
487
  const rows = stmts.getStoredGroupNoticeMessages.all(
@@ -493,7 +493,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
493
493
  },
494
494
 
495
495
  getMessagesByUser(
496
- userId: number,
496
+ userId: string,
497
497
  sessionId?: string,
498
498
  limit: number = 20,
499
499
  ): ChatMessage[] {
@@ -510,7 +510,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
510
510
  .reverse();
511
511
  },
512
512
 
513
- getAllMessagesByUser(userId: number, sessionId?: string): ChatMessage[] {
513
+ getAllMessagesByUser(userId: string, sessionId?: string): ChatMessage[] {
514
514
  const rows = sessionId
515
515
  ? (stmts.getAllMessagesByUserInSession.all({ $userId: userId, $sessionId: sessionId }) as any[])
516
516
  : (stmts.getAllMessagesByUser.all({ $userId: userId }) as any[]);
@@ -633,7 +633,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
633
633
  },
634
634
 
635
635
  getExpressionsByUser(
636
- userId: number,
636
+ userId: string,
637
637
  limit: number = 50,
638
638
  ): ExpressionRecord[] {
639
639
  const rows = stmts.getExpressionsByUser.all({ $userId: userId, $limit: limit }) as any[];
@@ -641,7 +641,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
641
641
  },
642
642
 
643
643
  replaceExpressionsByUser(
644
- userId: number,
644
+ userId: string,
645
645
  userName: string,
646
646
  expressions: Array<
647
647
  Pick<ExpressionRecord, "situation" | "style" | "example">
@@ -650,7 +650,7 @@ export async function initDatabase(): Promise<ChatDatabase> {
650
650
  const now = Date.now();
651
651
  const tx = db.transaction(
652
652
  (
653
- targetUserId: number,
653
+ targetUserId: string,
654
654
  targetUserName: string,
655
655
  rows: Array<
656
656
  Pick<ExpressionRecord, "situation" | "style" | "example">
@@ -17,10 +17,10 @@ export async function handleIdleCheckDebug(
17
17
  return;
18
18
  }
19
19
  const groupIdStr =
20
- e.message[0]?.text?.replace("/空闲检查", "")?.trim() || "";
21
- const targetGroupId = parseInt(groupIdStr, 10);
20
+ e.message[0]?.text?.replace(/^[./]空闲检查/, "")?.trim() || "";
21
+ const targetGroupId = String(groupIdStr).trim();
22
22
  if (!targetGroupId) {
23
- await e.reply("请指定群号,如:/空闲检查 123456");
23
+ await e.reply("请指定群 ID,如:.空闲检查 123456");
24
24
  return;
25
25
  }
26
26
 
@@ -61,7 +61,7 @@ export async function handleIdleCheckDebug(
61
61
 
62
62
  const targetMessage: TargetMessage = {
63
63
  userName: "系统",
64
- userId: 0,
64
+ userId: "",
65
65
  userRole: "member",
66
66
  content: "[No one in the group is talking? I'll answer!]",
67
67
  messageId: "",
@@ -73,7 +73,7 @@ export async function handleIdleCheckDebug(
73
73
  event: null,
74
74
  groupSessionId,
75
75
  groupId: targetGroupId,
76
- userId: 0,
76
+ userId: "",
77
77
  config: cfg,
78
78
  aiService: ctx.services!.ai as AIService,
79
79
  db: pluginCtx.db,
@@ -117,8 +117,8 @@ export async function handleIdleCheckDebug(
117
117
  result,
118
118
  groupId: targetGroupId,
119
119
  groupSessionId,
120
- userId: 0,
121
- selfId: e.self_id,
120
+ userId: "",
121
+ selfId: String(e.self_id ?? "").trim(),
122
122
  toolCtx,
123
123
  send: true,
124
124
  isLive: true,
@@ -35,8 +35,8 @@ export function createMessageHandler(
35
35
 
36
36
  return async (e: MessageEvent) => {
37
37
  const isGroup = e.message_type === "group";
38
- const groupId: number | undefined = isGroup
39
- ? Number(e.group_id)
38
+ const groupId: string | undefined = isGroup
39
+ ? String(e.group_id ?? "").trim() || undefined
40
40
  : undefined;
41
41
  const cfg = await getConfig(groupId);
42
42
  if (!isGroup && cfg.ignorePrivateChat) return;
@@ -44,13 +44,13 @@ export function createMessageHandler(
44
44
  if (!e?.message || !Array.isArray(e.message)) return;
45
45
 
46
46
  const text = ctx.text(e) || "";
47
- const userId: number = Number(e.user_id || e.sender?.user_id || 0);
47
+ const userId: string = String(e.user_id ?? e.sender?.user_id ?? "").trim();
48
48
 
49
- if (userId === Number(e.self_id || 0)) return;
49
+ if (!userId || userId === String(e.self_id ?? "").trim()) return;
50
50
 
51
51
  if (matchMessageCommands && matchMessageCommands(text).length > 0) return;
52
52
 
53
- if (text.startsWith("/空闲检查 ")) {
53
+ if (/^[./]空闲检查\s/.test(text)) {
54
54
  await handleIdleCheckDebug(pluginCtx, e, cfg);
55
55
  return;
56
56
  }
@@ -204,9 +204,7 @@ export function createMessageHandler(
204
204
 
205
205
  const atBot = shouldTrigger(e, text, cfg, ctx);
206
206
  const replyBot = ctx.pickReplyBot(e);
207
- const actorSelfId = replyBot
208
- ? Number(replyBot.bot_id)
209
- : Number(e.self_id || 0);
207
+ const actorSelfId = String(replyBot?.bot_id ?? e.self_id ?? "").trim();
210
208
  const quotedBot = isGroup ? await isQuotingBot(e, ctx) : null;
211
209
  const mentionedNickname =
212
210
  cfg.nicknames.length > 0 &&