mioku-plugin-chat 3.0.6 → 3.1.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/context.ts +5 -5
- package/core/base.ts +20 -20
- package/core/chat-engine.ts +14 -10
- package/core/chat-turn.ts +109 -37
- package/core/media/history-media.ts +14 -14
- package/core/media/image-compress.ts +38 -27
- package/core/media/segment.ts +2 -2
- package/core/prompt.ts +1 -1
- package/core/tools/info.ts +14 -7
- package/core/tools/web.ts +6 -9
- package/db.ts +13 -13
- package/handlers/idle-debug.ts +7 -7
- package/handlers/message.ts +6 -8
- package/handlers/poke.ts +15 -14
- package/humanize/emotion-agent.ts +5 -5
- package/humanize/expression.ts +6 -6
- package/humanize/index.ts +1 -1
- package/humanize/memory.ts +1 -1
- package/index.ts +52 -28
- package/manage/cooldown.ts +8 -8
- package/manage/group-structured-history.ts +2 -2
- package/manage/idle-check.ts +12 -11
- package/manage/queue-processor.ts +9 -8
- package/manage/rate-limit-guard.ts +2 -2
- package/manage/rate-limiter.ts +21 -21
- package/manage/session.ts +1 -1
- package/manage/types.ts +16 -16
- package/package.json +1 -1
- package/runtime/chat-runtime.ts +4 -4
- package/types.ts +11 -11
- package/utils/config.ts +4 -4
- package/utils/group-config.ts +3 -4
- package/utils/index.ts +2 -0
- package/utils/message.ts +112 -47
- package/utils/model.ts +31 -0
- package/utils/queue.ts +12 -11
|
@@ -4,7 +4,7 @@ import type { TargetMessage } from "../types";
|
|
|
4
4
|
|
|
5
5
|
export interface StructuredUserInput {
|
|
6
6
|
userName: string;
|
|
7
|
-
userId:
|
|
7
|
+
userId: string;
|
|
8
8
|
userRole?: string;
|
|
9
9
|
userTitle?: string;
|
|
10
10
|
content: string;
|
|
@@ -192,7 +192,7 @@ function formatStructuredUserContent(input: StructuredUserInput): string {
|
|
|
192
192
|
const lines = [
|
|
193
193
|
"[Group Member Message]",
|
|
194
194
|
`Name: ${input.userName || "unknown"}`,
|
|
195
|
-
`
|
|
195
|
+
`user_id: ${input.userId || "unknown"}`,
|
|
196
196
|
`Time: ${formatTimestamp(input.timestamp)}`,
|
|
197
197
|
];
|
|
198
198
|
|
package/manage/idle-check.ts
CHANGED
|
@@ -25,7 +25,7 @@ export class IdleCheckManager {
|
|
|
25
25
|
private groupLastBotMessageTime = new Map<string, number>();
|
|
26
26
|
private groupMessageCountAfterBot = new Map<string, number>();
|
|
27
27
|
private groupLastIdleCheckTime = new Map<string, number>();
|
|
28
|
-
private groupBotsMapping = new Map<string, Set<
|
|
28
|
+
private groupBotsMapping = new Map<string, Set<string>>();
|
|
29
29
|
private intervalHandle: NodeJS.Timeout | null = null;
|
|
30
30
|
|
|
31
31
|
private ctx: MiokuContext;
|
|
@@ -71,11 +71,11 @@ export class IdleCheckManager {
|
|
|
71
71
|
this.groupMessageCount.set(groupSessionId, count + 1);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
recordBotMessages(groupSessionId: string, count: number, selfId:
|
|
74
|
+
recordBotMessages(groupSessionId: string, count: number, selfId: string): void {
|
|
75
75
|
const current = this.groupMessageCountAfterBot.get(groupSessionId) ?? 0;
|
|
76
76
|
this.groupMessageCountAfterBot.set(groupSessionId, current + count);
|
|
77
77
|
let bots = this.groupBotsMapping.get(groupSessionId);
|
|
78
|
-
if (!bots) { bots = new Set<
|
|
78
|
+
if (!bots) { bots = new Set<string>(); this.groupBotsMapping.set(groupSessionId, bots); }
|
|
79
79
|
bots.add(selfId);
|
|
80
80
|
this.groupLastBotMessageTime.set(groupSessionId, Date.now());
|
|
81
81
|
}
|
|
@@ -106,14 +106,15 @@ export class IdleCheckManager {
|
|
|
106
106
|
|
|
107
107
|
const now = Date.now();
|
|
108
108
|
const checkInterval = 60_000;
|
|
109
|
-
const allBotIds = Array.from(this.ctx.bots).map((bot) =>
|
|
109
|
+
const allBotIds = Array.from(this.ctx.bots).map((bot) => String(bot.bot_id));
|
|
110
110
|
|
|
111
111
|
for (const [groupSessionId, lastTime] of this.groupLastActivityTime) {
|
|
112
112
|
const lastCheckTime =
|
|
113
113
|
this.groupLastIdleCheckTime.get(groupSessionId) ?? 0;
|
|
114
114
|
if (now - lastCheckTime < checkInterval) continue;
|
|
115
115
|
|
|
116
|
-
const groupId =
|
|
116
|
+
const groupId = String(groupSessionId.split(":")[1] ?? "").trim();
|
|
117
|
+
if (!groupId) continue;
|
|
117
118
|
const cfg = this.configProvider(groupId);
|
|
118
119
|
if (!cfg.planner?.enabled) continue;
|
|
119
120
|
if (!isGroupAllowed(groupId, cfg)) continue;
|
|
@@ -130,7 +131,7 @@ export class IdleCheckManager {
|
|
|
130
131
|
cfg.planner.idleCheckBotIds ??
|
|
131
132
|
baseCfg.planner?.idleCheckBotIds ??
|
|
132
133
|
allBotIds;
|
|
133
|
-
const enabledBotIds = idleCheckBotIds.filter((id:
|
|
134
|
+
const enabledBotIds = idleCheckBotIds.filter((id: string) =>
|
|
134
135
|
allBotIds.includes(id),
|
|
135
136
|
);
|
|
136
137
|
|
|
@@ -193,8 +194,8 @@ export class IdleCheckManager {
|
|
|
193
194
|
|
|
194
195
|
private async processIdleCheckTurn(
|
|
195
196
|
groupSessionId: string,
|
|
196
|
-
groupId:
|
|
197
|
-
selfId:
|
|
197
|
+
groupId: string,
|
|
198
|
+
selfId: string,
|
|
198
199
|
cfg: ChatConfig,
|
|
199
200
|
scheduledLastActivity: number,
|
|
200
201
|
scheduledAt: number,
|
|
@@ -234,7 +235,7 @@ export class IdleCheckManager {
|
|
|
234
235
|
|
|
235
236
|
const targetMessage: TargetMessage = {
|
|
236
237
|
userName: "system",
|
|
237
|
-
userId:
|
|
238
|
+
userId: "",
|
|
238
239
|
userRole: "member",
|
|
239
240
|
content: "[No one in the group is talking? I'll answer!]",
|
|
240
241
|
messageId: "",
|
|
@@ -246,7 +247,7 @@ export class IdleCheckManager {
|
|
|
246
247
|
event: null,
|
|
247
248
|
groupSessionId,
|
|
248
249
|
groupId,
|
|
249
|
-
userId:
|
|
250
|
+
userId: "",
|
|
250
251
|
config: cfg,
|
|
251
252
|
aiService: this.aiService,
|
|
252
253
|
db: this.db,
|
|
@@ -292,7 +293,7 @@ export class IdleCheckManager {
|
|
|
292
293
|
result,
|
|
293
294
|
groupId,
|
|
294
295
|
groupSessionId,
|
|
295
|
-
userId:
|
|
296
|
+
userId: "",
|
|
296
297
|
selfId,
|
|
297
298
|
toolCtx,
|
|
298
299
|
send: true,
|
|
@@ -25,7 +25,7 @@ import { finalizeChatTurn } from "../core/chat-turn";
|
|
|
25
25
|
import { extractContent, getBotRole } from "../utils";
|
|
26
26
|
|
|
27
27
|
interface DynamicDelayQueueData {
|
|
28
|
-
messages: Array<{ event: any; content: string; userName: string; userId:
|
|
28
|
+
messages: Array<{ event: any; content: string; userName: string; userId: string; messageId: string; timestamp: number }>;
|
|
29
29
|
timer: NodeJS.Timeout | null;
|
|
30
30
|
delayUntil: number;
|
|
31
31
|
}
|
|
@@ -91,7 +91,7 @@ export class QueueProcessor {
|
|
|
91
91
|
queueData.messages.push({ event, content, userName, userId: event.user_id, messageId: event.message_id, timestamp: Date.now() });
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
startDynamicDelayTimer(groupSessionId: string, groupId:
|
|
94
|
+
startDynamicDelayTimer(groupSessionId: string, groupId: string, delayMs: number, selfId: string): void {
|
|
95
95
|
let queueData = this.dynamicDelayQueues.get(groupSessionId);
|
|
96
96
|
if (!queueData) {
|
|
97
97
|
queueData = { messages: [], timer: null, delayUntil: Date.now() + delayMs };
|
|
@@ -132,7 +132,7 @@ export class QueueProcessor {
|
|
|
132
132
|
return queue != null && Date.now() < queue.delayUntil;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
scheduleQueuedMessages(groupSessionId: string, selfId:
|
|
135
|
+
scheduleQueuedMessages(groupSessionId: string, selfId: string): void {
|
|
136
136
|
void this.sessionTurnScheduler
|
|
137
137
|
.run(
|
|
138
138
|
groupSessionId,
|
|
@@ -156,8 +156,8 @@ export class QueueProcessor {
|
|
|
156
156
|
|
|
157
157
|
private async processDynamicDelayMessages(
|
|
158
158
|
groupSessionId: string,
|
|
159
|
-
groupId:
|
|
160
|
-
selfId:
|
|
159
|
+
groupId: string,
|
|
160
|
+
selfId: string,
|
|
161
161
|
messages: DynamicDelayQueueData["messages"],
|
|
162
162
|
): Promise<void> {
|
|
163
163
|
this.ctx.logger.info(`[DynamicDelay] group ${groupId} processes ${messages.length} delayed messages`);
|
|
@@ -217,7 +217,7 @@ export class QueueProcessor {
|
|
|
217
217
|
});
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
async processQueuedMessages(groupSessionId: string, selfId:
|
|
220
|
+
async processQueuedMessages(groupSessionId: string, selfId: string): Promise<void> {
|
|
221
221
|
try {
|
|
222
222
|
const queue = this.queueManager.getQueue(groupSessionId);
|
|
223
223
|
if (!queue || queue.length === 0) {
|
|
@@ -225,7 +225,8 @@ export class QueueProcessor {
|
|
|
225
225
|
return;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
const groupId =
|
|
228
|
+
const groupId = String(groupSessionId.split(":")[1] ?? "").trim();
|
|
229
|
+
if (!groupId) return;
|
|
229
230
|
this.ctx.logger.info(`[Queue] group ${groupSessionId} batch ${queue.length} messages`);
|
|
230
231
|
|
|
231
232
|
const queuedContents: string[] = [];
|
|
@@ -255,7 +256,7 @@ export class QueueProcessor {
|
|
|
255
256
|
const mergedContent = queuedContents.join("\n");
|
|
256
257
|
|
|
257
258
|
const targetMessage: TargetMessage = {
|
|
258
|
-
userName, userId: firstItem.event.user_id
|
|
259
|
+
userName, userId: String(firstItem.event.user_id ?? firstItem.event.sender?.user_id ?? "").trim(),
|
|
259
260
|
userRole: firstItem.event.sender?.role || "member", content: mergedContent,
|
|
260
261
|
messageId: firstItem.event.message_id, timestamp: Date.now(),
|
|
261
262
|
};
|
package/manage/rate-limiter.ts
CHANGED
|
@@ -13,16 +13,16 @@ const DEFAULT_AI_REQUEST_LIMITS: AIRequestLimitConfig = {
|
|
|
13
13
|
windowMs: 60_000,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export type ChatConfigProvider = (groupId?:
|
|
16
|
+
export type ChatConfigProvider = (groupId?: string) => ChatConfig;
|
|
17
17
|
|
|
18
18
|
export class RateLimiter {
|
|
19
|
-
private userTriggers: Map<
|
|
20
|
-
private userMessages: Map<
|
|
19
|
+
private userTriggers: Map<string, number[]> = new Map();
|
|
20
|
+
private userMessages: Map<string, { content: string; timestamp: number }[]> =
|
|
21
21
|
new Map();
|
|
22
|
-
private groupLastResponse: Map<
|
|
23
|
-
private groupInteractions: Map<
|
|
24
|
-
private userAiRequests: Map<
|
|
25
|
-
private groupAiRequests: Map<
|
|
22
|
+
private groupLastResponse: Map<string, number> = new Map();
|
|
23
|
+
private groupInteractions: Map<string, Map<string, number[]>> = new Map();
|
|
24
|
+
private userAiRequests: Map<string, number[]> = new Map();
|
|
25
|
+
private groupAiRequests: Map<string, number[]> = new Map();
|
|
26
26
|
|
|
27
27
|
private readonly maxTriggersPerWindow: number;
|
|
28
28
|
private readonly windowMs: number;
|
|
@@ -30,13 +30,13 @@ export class RateLimiter {
|
|
|
30
30
|
private readonly groupCooldownMs: number;
|
|
31
31
|
private readonly cleanupTimer: ReturnType<typeof setInterval>;
|
|
32
32
|
private getConfig: ChatConfigProvider;
|
|
33
|
-
private getQueueLengthFn: ((groupId:
|
|
33
|
+
private getQueueLengthFn: ((groupId: string) => number) | null = null;
|
|
34
34
|
|
|
35
35
|
setConfigProvider(provider: ChatConfigProvider): void {
|
|
36
36
|
this.getConfig = provider;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
setQueueLengthGetter(fn: (groupId:
|
|
39
|
+
setQueueLengthGetter(fn: (groupId: string) => number): void {
|
|
40
40
|
this.getQueueLengthFn = fn;
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -58,17 +58,17 @@ export class RateLimiter {
|
|
|
58
58
|
this.cleanupTimer = setInterval(() => this.cleanup(), 300_000);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
private getDynamicDelay(groupId?:
|
|
61
|
+
private getDynamicDelay(groupId?: string): DynamicDelayConfig {
|
|
62
62
|
return this.getConfig(groupId)?.dynamicDelay ?? DEFAULT_DYNAMIC_DELAY;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
private getAiRequestLimits(groupId?:
|
|
65
|
+
private getAiRequestLimits(groupId?: string): AIRequestLimitConfig {
|
|
66
66
|
return this.getConfig(groupId)?.aiRequestLimits ?? DEFAULT_AI_REQUEST_LIMITS;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
canProcess(
|
|
70
|
-
userId:
|
|
71
|
-
groupId:
|
|
70
|
+
userId: string,
|
|
71
|
+
groupId: string | undefined,
|
|
72
72
|
content: string,
|
|
73
73
|
): boolean {
|
|
74
74
|
const now = Date.now();
|
|
@@ -93,7 +93,7 @@ export class RateLimiter {
|
|
|
93
93
|
return !recentSame;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
record(userId:
|
|
96
|
+
record(userId: string, groupId: string | undefined, content: string): void {
|
|
97
97
|
const now = Date.now();
|
|
98
98
|
|
|
99
99
|
const triggers = this.userTriggers.get(userId) ?? [];
|
|
@@ -110,7 +110,7 @@ export class RateLimiter {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
recordInteraction(groupId:
|
|
113
|
+
recordInteraction(groupId: string, userId: string): void {
|
|
114
114
|
const dynamicDelay = this.getDynamicDelay(groupId);
|
|
115
115
|
if (!dynamicDelay.enabled) return;
|
|
116
116
|
|
|
@@ -129,7 +129,7 @@ export class RateLimiter {
|
|
|
129
129
|
groupUsers.set(userId, timestamps);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
canRunAIRequest(userId?:
|
|
132
|
+
canRunAIRequest(userId?: string, groupId?: string): boolean {
|
|
133
133
|
const now = Date.now();
|
|
134
134
|
const { userRpm, groupRpm, windowMs } = this.getAiRequestLimits(groupId);
|
|
135
135
|
|
|
@@ -154,7 +154,7 @@ export class RateLimiter {
|
|
|
154
154
|
return true;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
recordAIRequest(userId?:
|
|
157
|
+
recordAIRequest(userId?: string, groupId?: string): void {
|
|
158
158
|
const now = Date.now();
|
|
159
159
|
const { windowMs } = this.getAiRequestLimits(groupId);
|
|
160
160
|
|
|
@@ -175,7 +175,7 @@ export class RateLimiter {
|
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
getInteractionCount(groupId:
|
|
178
|
+
getInteractionCount(groupId: string): number {
|
|
179
179
|
const now = Date.now();
|
|
180
180
|
const { interactionWindowMs: windowMs } = this.getDynamicDelay(groupId);
|
|
181
181
|
|
|
@@ -199,7 +199,7 @@ export class RateLimiter {
|
|
|
199
199
|
return count;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
calculateDelay(groupId:
|
|
202
|
+
calculateDelay(groupId: string): number {
|
|
203
203
|
const dynamicDelay = this.getDynamicDelay(groupId);
|
|
204
204
|
if (!dynamicDelay.enabled) return 0;
|
|
205
205
|
|
|
@@ -211,7 +211,7 @@ export class RateLimiter {
|
|
|
211
211
|
return Math.min(delay, maxDelayMs);
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
getDelayInfo(groupId:
|
|
214
|
+
getDelayInfo(groupId: string): {
|
|
215
215
|
delayMs: number;
|
|
216
216
|
interactionCount: number;
|
|
217
217
|
shouldDelay: boolean;
|
|
@@ -225,7 +225,7 @@ export class RateLimiter {
|
|
|
225
225
|
};
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
clearGroupInteractions(groupId:
|
|
228
|
+
clearGroupInteractions(groupId: string): void {
|
|
229
229
|
this.groupInteractions.delete(groupId);
|
|
230
230
|
}
|
|
231
231
|
|
package/manage/session.ts
CHANGED
|
@@ -17,7 +17,7 @@ export class SessionManager {
|
|
|
17
17
|
/**
|
|
18
18
|
* 获取或创建会话
|
|
19
19
|
*/
|
|
20
|
-
getOrCreate(id: string, type: SessionType, targetId:
|
|
20
|
+
getOrCreate(id: string, type: SessionType, targetId: string): SessionMeta {
|
|
21
21
|
// 先查缓存
|
|
22
22
|
if (this.cache.has(id)) {
|
|
23
23
|
return this.touch(id);
|
package/manage/types.ts
CHANGED
|
@@ -31,27 +31,27 @@ export type HistoryMediaOptions = {
|
|
|
31
31
|
export type RunRateLimitGuard = <T>(
|
|
32
32
|
request: () => Promise<T>,
|
|
33
33
|
opts?: {
|
|
34
|
-
userId?:
|
|
35
|
-
groupId?:
|
|
34
|
+
userId?: string;
|
|
35
|
+
groupId?: string;
|
|
36
36
|
label?: string;
|
|
37
37
|
skipRetryOnRateLimit?: boolean;
|
|
38
38
|
},
|
|
39
39
|
) => Promise<T | null>;
|
|
40
40
|
|
|
41
41
|
export type GetGroupHistoryMessages = (
|
|
42
|
-
groupId:
|
|
42
|
+
groupId: string,
|
|
43
43
|
groupSessionId: string,
|
|
44
44
|
ctx: MiokuContext,
|
|
45
45
|
historyCount: number,
|
|
46
46
|
db: ChatDatabase,
|
|
47
|
-
selfId:
|
|
47
|
+
selfId: string,
|
|
48
48
|
mediaOptions?: HistoryMediaOptions,
|
|
49
49
|
) => Promise<{ history: ChatMessage[] }>;
|
|
50
50
|
|
|
51
51
|
export type GetGroupInfoData = (
|
|
52
52
|
ctx: MiokuContext,
|
|
53
|
-
groupId:
|
|
54
|
-
selfId:
|
|
53
|
+
groupId: string,
|
|
54
|
+
selfId: string,
|
|
55
55
|
fallbackGroupName?: string,
|
|
56
56
|
) => Promise<GroupInfoResult>;
|
|
57
57
|
|
|
@@ -60,16 +60,16 @@ export type GetHumanizeContexts = (
|
|
|
60
60
|
groupSessionId: string,
|
|
61
61
|
userName: string,
|
|
62
62
|
history: ChatMessage[],
|
|
63
|
-
triggerUserId?:
|
|
63
|
+
triggerUserId?: string,
|
|
64
64
|
) => Promise<HumanizeContextsResult>;
|
|
65
65
|
|
|
66
66
|
export type SendAIResponse = (
|
|
67
67
|
options: SendAIResponseOptions,
|
|
68
|
-
selfId:
|
|
68
|
+
selfId: string,
|
|
69
69
|
) => Promise<Array<string | undefined>>;
|
|
70
70
|
|
|
71
71
|
export type SaveBotMessages = (
|
|
72
|
-
groupId:
|
|
72
|
+
groupId: string,
|
|
73
73
|
groupSessionId: string,
|
|
74
74
|
messages: string[],
|
|
75
75
|
timestamp: number,
|
|
@@ -82,28 +82,28 @@ export type SaveBotMessages = (
|
|
|
82
82
|
|
|
83
83
|
export type SendEmoji = (
|
|
84
84
|
ctx: MiokuContext,
|
|
85
|
-
groupId:
|
|
85
|
+
groupId: string,
|
|
86
86
|
emojiPath: string | null | undefined,
|
|
87
87
|
bot?: import("mioku").Bot,
|
|
88
88
|
) => Promise<void>;
|
|
89
89
|
|
|
90
90
|
export type SendMessage = (
|
|
91
91
|
ctx: MiokuContext,
|
|
92
|
-
groupId:
|
|
93
|
-
userId:
|
|
92
|
+
groupId: string | undefined,
|
|
93
|
+
userId: string,
|
|
94
94
|
text: string,
|
|
95
95
|
config: ChatConfig,
|
|
96
|
-
selfId:
|
|
96
|
+
selfId: string,
|
|
97
97
|
audioService?: import("mioku-service-audio").AudioServiceApi,
|
|
98
98
|
) => Promise<void>;
|
|
99
99
|
|
|
100
100
|
export type BuildToolContext = (options: {
|
|
101
101
|
ctx: MiokuContext;
|
|
102
102
|
event: any;
|
|
103
|
-
selfId:
|
|
103
|
+
selfId: string;
|
|
104
104
|
groupSessionId: string;
|
|
105
|
-
groupId?:
|
|
106
|
-
userId:
|
|
105
|
+
groupId?: string;
|
|
106
|
+
userId: string;
|
|
107
107
|
config: ChatConfig;
|
|
108
108
|
aiService: AIService;
|
|
109
109
|
db: ChatDatabase;
|
package/package.json
CHANGED
package/runtime/chat-runtime.ts
CHANGED
|
@@ -12,21 +12,21 @@ import { executeChatRuntimeRequest } from "../core/chat-turn";
|
|
|
12
12
|
|
|
13
13
|
function resolveRuntimeGroupId(
|
|
14
14
|
options: ChatRuntimeNoticeOptions | ChatRuntimeInformationRequestOptions,
|
|
15
|
-
):
|
|
15
|
+
): string | undefined {
|
|
16
16
|
if ("event" in options) {
|
|
17
17
|
const event = options.event;
|
|
18
18
|
if (event?.kind !== "message" || event.message_type !== "group") {
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
21
|
-
const groupId
|
|
22
|
-
return
|
|
21
|
+
const groupId = String(event.group_id ?? "").trim();
|
|
22
|
+
return groupId || undefined;
|
|
23
23
|
}
|
|
24
24
|
return "groupId" in options ? options.groupId : undefined;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function createChatRuntime(
|
|
28
28
|
pluginCtx: ChatPluginContext,
|
|
29
|
-
getConfig: (groupId?:
|
|
29
|
+
getConfig: (groupId?: string) => Promise<ChatConfig>,
|
|
30
30
|
): ChatRuntime {
|
|
31
31
|
return {
|
|
32
32
|
async requestInformation(
|
package/types.ts
CHANGED
|
@@ -56,7 +56,7 @@ export interface PlannerConfig {
|
|
|
56
56
|
// 群聊记录保底消息数量
|
|
57
57
|
idleMessageCount: number;
|
|
58
58
|
// 空闲检查的 bot ID 列表
|
|
59
|
-
idleCheckBotIds:
|
|
59
|
+
idleCheckBotIds: string[];
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -183,9 +183,9 @@ export interface ChatConfig {
|
|
|
183
183
|
webReader: WebReaderConfig;
|
|
184
184
|
audio: AudioConfig;
|
|
185
185
|
historyCount: number;
|
|
186
|
-
blacklistGroups:
|
|
187
|
-
whitelistGroups:
|
|
188
|
-
mediaAnalysisBlacklistUsers:
|
|
186
|
+
blacklistGroups: string[];
|
|
187
|
+
whitelistGroups: string[];
|
|
188
|
+
mediaAnalysisBlacklistUsers: string[];
|
|
189
189
|
maxSessions: number;
|
|
190
190
|
maxIterations: number;
|
|
191
191
|
enableExternalSkills: boolean;
|
|
@@ -249,7 +249,7 @@ export type SessionType = "group" | "personal";
|
|
|
249
249
|
export interface SessionMeta {
|
|
250
250
|
id: string; // "group:{group_id}" 或 "personal:{user_id}"
|
|
251
251
|
type: SessionType;
|
|
252
|
-
targetId:
|
|
252
|
+
targetId: string; // group_id 或 user_id
|
|
253
253
|
createdAt: number;
|
|
254
254
|
updatedAt: number;
|
|
255
255
|
compressedContext: string | null;
|
|
@@ -263,11 +263,11 @@ export interface ChatMessage {
|
|
|
263
263
|
sessionId: string;
|
|
264
264
|
role: "user" | "assistant" | "system";
|
|
265
265
|
content: string; // 存储时统一为字符串
|
|
266
|
-
userId?:
|
|
266
|
+
userId?: string;
|
|
267
267
|
userName?: string;
|
|
268
268
|
userRole?: string; // "owner" | "admin" | "member"
|
|
269
269
|
userTitle?: string;
|
|
270
|
-
groupId?:
|
|
270
|
+
groupId?: string;
|
|
271
271
|
groupName?: string;
|
|
272
272
|
timestamp: number;
|
|
273
273
|
messageId?: string; // 消息 id
|
|
@@ -278,7 +278,7 @@ export interface ChatMessage {
|
|
|
278
278
|
*/
|
|
279
279
|
export interface TargetMessage {
|
|
280
280
|
userName: string;
|
|
281
|
-
userId:
|
|
281
|
+
userId: string;
|
|
282
282
|
userRole: string;
|
|
283
283
|
userTitle?: string;
|
|
284
284
|
content: string;
|
|
@@ -303,8 +303,8 @@ export interface ToolContext {
|
|
|
303
303
|
ctx: MiokuContext;
|
|
304
304
|
event: any;
|
|
305
305
|
sessionId: string;
|
|
306
|
-
groupId?:
|
|
307
|
-
userId:
|
|
306
|
+
groupId?: string;
|
|
307
|
+
userId: string;
|
|
308
308
|
triggerSkillRole: SkillPermissionRole;
|
|
309
309
|
config: ChatConfig;
|
|
310
310
|
aiService: AIService;
|
|
@@ -364,7 +364,7 @@ export interface TopicRecord {
|
|
|
364
364
|
export interface ExpressionRecord {
|
|
365
365
|
id?: number;
|
|
366
366
|
sessionId: string;
|
|
367
|
-
userId:
|
|
367
|
+
userId: string;
|
|
368
368
|
userName: string;
|
|
369
369
|
situation: string; // 使用场景
|
|
370
370
|
style: string; // 表达风格
|
package/utils/config.ts
CHANGED
|
@@ -33,20 +33,20 @@ export function mergeChatConfig<T extends Record<string, any>>(
|
|
|
33
33
|
return result as T;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export function normalizeIdList(input: unknown):
|
|
36
|
+
export function normalizeIdList(input: unknown): string[] {
|
|
37
37
|
if (!Array.isArray(input)) return [];
|
|
38
38
|
return Array.from(
|
|
39
39
|
new Set(
|
|
40
40
|
input
|
|
41
|
-
.map((item) =>
|
|
42
|
-
.filter((id) =>
|
|
41
|
+
.map((item) => String(item ?? "").trim())
|
|
42
|
+
.filter((id) => id.length > 0),
|
|
43
43
|
),
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export function normalizeMediaAnalysisBlacklist(
|
|
48
48
|
config: Record<string, any>,
|
|
49
|
-
):
|
|
49
|
+
): string[] {
|
|
50
50
|
const current = config.mediaAnalysisBlacklistUsers;
|
|
51
51
|
const legacy = config.imageAnalysisBlacklistUsers;
|
|
52
52
|
const source =
|
package/utils/group-config.ts
CHANGED
|
@@ -70,10 +70,9 @@ export function mergeGroupOverrides(
|
|
|
70
70
|
/**
|
|
71
71
|
* 从 sessionId(如 "group:123")提取群号,个人会话返回 undefined
|
|
72
72
|
*/
|
|
73
|
-
export function extractGroupIdFromSession(sessionId: string):
|
|
73
|
+
export function extractGroupIdFromSession(sessionId: string): string | undefined {
|
|
74
74
|
if (!sessionId || typeof sessionId !== "string") return undefined;
|
|
75
75
|
if (!sessionId.startsWith("group:")) return undefined;
|
|
76
|
-
const raw = sessionId.slice("group:".length);
|
|
77
|
-
|
|
78
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
76
|
+
const raw = sessionId.slice("group:".length).trim();
|
|
77
|
+
return raw.length > 0 ? raw : undefined;
|
|
79
78
|
}
|