mioku-plugin-chat 2.5.2 → 2.7.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/configs/groups.ts +5 -0
- package/configs/personalization.ts +1 -1
- package/context.ts +7 -3
- package/core/base.ts +1 -1
- package/core/chat-engine.ts +18 -7
- package/core/chat-turn.ts +28 -10
- package/core/media/image-analyzer.ts +63 -397
- package/core/prompt.ts +11 -20
- package/core/tools/web.ts +1 -1
- package/db.ts +8 -12
- package/handlers/idle-debug.ts +96 -97
- package/handlers/message.ts +38 -37
- package/handlers/poke.ts +104 -126
- package/humanize/emoji-agent.ts +210 -321
- package/humanize/emotion-agent.ts +33 -26
- package/humanize/expression.ts +24 -16
- package/humanize/index.ts +9 -8
- package/humanize/memory.ts +10 -7
- package/humanize/planner.ts +11 -16
- package/humanize/topic.ts +22 -15
- package/index.ts +120 -45
- package/manage/cooldown.ts +83 -116
- package/manage/idle-check.ts +173 -75
- package/manage/queue-processor.ts +92 -44
- package/manage/rate-limiter.ts +56 -80
- package/manage/session-turn-scheduler.ts +130 -0
- package/package.json +1 -1
- package/runtime/chat-runtime.ts +15 -3
- package/types.ts +25 -19
- package/utils/config.ts +57 -0
- package/utils/group-config.ts +70 -0
- package/utils/message.ts +4 -7
- package/utils/queue.ts +5 -0
package/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { definePlugin } from "mioki";
|
|
|
2
2
|
import type { MiokiContext } from "mioki";
|
|
3
3
|
import type { AIInstance, AIService, ConfigService, ScreenshotService } from "mioku";
|
|
4
4
|
import { getPluginRuntimeState } from "mioku";
|
|
5
|
-
import type { ChatConfig, ChatMessage, TargetMessage } from "./types";
|
|
5
|
+
import type { ChatConfig, ChatMessage, ChatGroupsFile, TargetMessage } from "./types";
|
|
6
6
|
import { initDatabase } from "./db";
|
|
7
7
|
import { SessionManager } from "./manage/session";
|
|
8
8
|
import { RateLimiter } from "./manage/rate-limiter";
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { CooldownManager } from "./manage/cooldown";
|
|
24
24
|
import { IdleCheckManager } from "./manage/idle-check";
|
|
25
25
|
import { QueueProcessor } from "./manage/queue-processor";
|
|
26
|
+
import { SessionTurnScheduler } from "./manage/session-turn-scheduler";
|
|
26
27
|
import { ChatDatabaseCleanup, DEFAULT_CLEANUP_CONFIG } from "./manage/cleanup";
|
|
27
28
|
import {
|
|
28
29
|
GroupStructuredHistoryManager,
|
|
@@ -32,23 +33,20 @@ import {
|
|
|
32
33
|
import { BASE_CONFIG } from "./configs/base";
|
|
33
34
|
import { SETTINGS_CONFIG } from "./configs/settings";
|
|
34
35
|
import { PERSONALIZATION_CONFIG } from "./configs/personalization";
|
|
36
|
+
import { DEFAULT_GROUPS_CONFIG } from "./configs/groups";
|
|
35
37
|
import { RateLimitGuard } from "./manage/rate-limit-guard";
|
|
36
38
|
import { createChatRuntime } from "./runtime/chat-runtime";
|
|
37
39
|
import { createMessageHandler } from "./handlers/message";
|
|
38
40
|
import { createPokeHandler } from "./handlers/poke";
|
|
39
41
|
import { buildHistoryMediaOptions } from "./core/media/segment";
|
|
42
|
+
import type { ChatConfigProvider } from "./humanize";
|
|
40
43
|
import type { ChatPluginContext, ChatHandlerState } from "./context";
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.map((item) => Math.floor(Number(item)))
|
|
48
|
-
.filter((id) => Number.isFinite(id) && id > 0),
|
|
49
|
-
),
|
|
50
|
-
);
|
|
51
|
-
}
|
|
44
|
+
import { mergeGroupOverrides } from "./utils/group-config";
|
|
45
|
+
import {
|
|
46
|
+
mergeChatConfig,
|
|
47
|
+
normalizeIdList,
|
|
48
|
+
normalizeMediaAnalysisBlacklist,
|
|
49
|
+
} from "./utils/config";
|
|
52
50
|
|
|
53
51
|
export default definePlugin({
|
|
54
52
|
name: "chat",
|
|
@@ -66,27 +64,40 @@ export default definePlugin({
|
|
|
66
64
|
await configService.registerConfig("chat", "base", BASE_CONFIG);
|
|
67
65
|
await configService.registerConfig("chat", "settings", SETTINGS_CONFIG);
|
|
68
66
|
await configService.registerConfig("chat", "personalization", PERSONALIZATION_CONFIG);
|
|
67
|
+
await configService.registerConfig("chat", "groups", DEFAULT_GROUPS_CONFIG);
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
let cachedBaseConfig: ChatConfig | null = null;
|
|
71
|
+
let cachedGroupsConfig: ChatGroupsFile | null = null;
|
|
72
|
+
|
|
73
|
+
const buildGlobalConfig = async (): Promise<ChatConfig> => {
|
|
72
74
|
if (!configService) {
|
|
73
|
-
return
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
return mergeChatConfig(
|
|
76
|
+
mergeChatConfig(
|
|
77
|
+
mergeChatConfig({} as ChatConfig, BASE_CONFIG),
|
|
78
|
+
SETTINGS_CONFIG,
|
|
79
|
+
),
|
|
80
|
+
PERSONALIZATION_CONFIG,
|
|
81
|
+
);
|
|
78
82
|
}
|
|
79
|
-
const base = await configService.getConfig("chat", "base");
|
|
80
|
-
const settings = await configService.getConfig("chat", "settings");
|
|
81
|
-
const personalization =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
const base = (await configService.getConfig("chat", "base")) ?? {};
|
|
84
|
+
const settings = (await configService.getConfig("chat", "settings")) ?? {};
|
|
85
|
+
const personalization =
|
|
86
|
+
(await configService.getConfig("chat", "personalization")) ?? {};
|
|
87
|
+
const mergedDefaults = mergeChatConfig(
|
|
88
|
+
mergeChatConfig(
|
|
89
|
+
mergeChatConfig({} as ChatConfig, BASE_CONFIG),
|
|
90
|
+
SETTINGS_CONFIG,
|
|
91
|
+
),
|
|
92
|
+
PERSONALIZATION_CONFIG,
|
|
93
|
+
);
|
|
94
|
+
const merged = mergeChatConfig(
|
|
95
|
+
mergeChatConfig(
|
|
96
|
+
mergeChatConfig(mergedDefaults, settings),
|
|
97
|
+
personalization,
|
|
98
|
+
),
|
|
99
|
+
base,
|
|
100
|
+
) as ChatConfig;
|
|
90
101
|
|
|
91
102
|
if (typeof merged.stream !== "boolean") merged.stream = true;
|
|
92
103
|
if (typeof merged.enableMarkdownScreenshot !== "boolean") {
|
|
@@ -101,14 +112,69 @@ export default definePlugin({
|
|
|
101
112
|
}
|
|
102
113
|
merged.whitelistGroups = normalizeIdList(merged.whitelistGroups);
|
|
103
114
|
merged.blacklistGroups = normalizeIdList(merged.blacklistGroups);
|
|
104
|
-
merged.mediaAnalysisBlacklistUsers =
|
|
105
|
-
merged
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
return merged as ChatConfig;
|
|
115
|
+
merged.mediaAnalysisBlacklistUsers =
|
|
116
|
+
normalizeMediaAnalysisBlacklist(merged as Record<string, any>);
|
|
117
|
+
delete (merged as any).imageAnalysisBlacklistUsers;
|
|
118
|
+
return merged;
|
|
109
119
|
};
|
|
110
120
|
|
|
111
|
-
const
|
|
121
|
+
const refreshGroupsCache = async (): Promise<void> => {
|
|
122
|
+
if (!configService) {
|
|
123
|
+
cachedGroupsConfig = DEFAULT_GROUPS_CONFIG;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const raw = await configService.getConfig("chat", "groups");
|
|
127
|
+
cachedGroupsConfig =
|
|
128
|
+
raw && typeof raw === "object" && raw.groups && typeof raw.groups === "object"
|
|
129
|
+
? (raw as ChatGroupsFile)
|
|
130
|
+
: DEFAULT_GROUPS_CONFIG;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const refreshBaseCache = async (): Promise<void> => {
|
|
134
|
+
cachedBaseConfig = await buildGlobalConfig();
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
await refreshBaseCache();
|
|
138
|
+
await refreshGroupsCache();
|
|
139
|
+
|
|
140
|
+
if (configService) {
|
|
141
|
+
configService.onConfigChange("chat", "base", () => {
|
|
142
|
+
refreshBaseCache().catch((err) =>
|
|
143
|
+
ctx.logger.error(`刷新 chat/base 缓存失败: ${err}`),
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
configService.onConfigChange("chat", "settings", () => {
|
|
147
|
+
refreshBaseCache().catch((err) =>
|
|
148
|
+
ctx.logger.error(`刷新 chat/settings 缓存失败: ${err}`),
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
configService.onConfigChange("chat", "personalization", () => {
|
|
152
|
+
refreshBaseCache().catch((err) =>
|
|
153
|
+
ctx.logger.error(`刷新 chat/personalization 缓存失败: ${err}`),
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
configService.onConfigChange("chat", "groups", () => {
|
|
157
|
+
refreshGroupsCache().catch((err) =>
|
|
158
|
+
ctx.logger.error(`刷新 chat/groups 缓存失败: ${err}`),
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const configProvider: ChatConfigProvider = (groupId?: number) => {
|
|
164
|
+
const base = cachedBaseConfig;
|
|
165
|
+
if (!base) return PERSONALIZATION_CONFIG as unknown as ChatConfig;
|
|
166
|
+
if (groupId === undefined) return base;
|
|
167
|
+
const overrides = cachedGroupsConfig?.groups?.[String(groupId)];
|
|
168
|
+
return mergeGroupOverrides(base, overrides);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const getConfig = async (groupId?: number): Promise<ChatConfig> => {
|
|
172
|
+
if (!cachedBaseConfig) await refreshBaseCache();
|
|
173
|
+
return configProvider(groupId);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const defaultConfig = configProvider();
|
|
177
|
+
const config = defaultConfig;
|
|
112
178
|
|
|
113
179
|
if (!config.apiKey) {
|
|
114
180
|
ctx.logger.warn("聊天插件未配置 API Key,请在 config/chat/base.json 中配置");
|
|
@@ -119,9 +185,12 @@ export default definePlugin({
|
|
|
119
185
|
const sessionManager = new SessionManager(db, config.maxSessions);
|
|
120
186
|
const queueManager = new MessageQueueManager();
|
|
121
187
|
const rateLimiter = new RateLimiter({
|
|
122
|
-
|
|
123
|
-
|
|
188
|
+
maxTriggersPerWindow: 5,
|
|
189
|
+
windowMs: 60_000,
|
|
190
|
+
dedupWindowMs: 30_000,
|
|
191
|
+
groupCooldownMs: 1_000,
|
|
124
192
|
});
|
|
193
|
+
rateLimiter.setConfigProvider(configProvider);
|
|
125
194
|
const skillManager = new SkillSessionManager();
|
|
126
195
|
|
|
127
196
|
rateLimiter.setQueueLengthGetter((groupId: number) =>
|
|
@@ -172,17 +241,19 @@ export default definePlugin({
|
|
|
172
241
|
});
|
|
173
242
|
}
|
|
174
243
|
|
|
175
|
-
const humanize = new HumanizeEngine(
|
|
244
|
+
const humanize = new HumanizeEngine(workAIInstance, db, configProvider);
|
|
176
245
|
await humanize.init();
|
|
177
246
|
|
|
178
247
|
const pokeCooldowns = new Map<number, number>();
|
|
179
248
|
const processingSet = new Set<string>();
|
|
249
|
+
const sessionTurnScheduler = new SessionTurnScheduler();
|
|
180
250
|
const groupStructuredHistory = new GroupStructuredHistoryManager();
|
|
181
251
|
const rateLimitGuard = new RateLimitGuard(rateLimiter, ctx.logger);
|
|
182
252
|
const runWithRateLimitGuard = rateLimitGuard.run.bind(rateLimitGuard);
|
|
183
253
|
|
|
184
254
|
const pluginCtx = {
|
|
185
|
-
ctx,
|
|
255
|
+
ctx, defaultConfig, configProvider, getConfig,
|
|
256
|
+
db,
|
|
186
257
|
aiInstance: mainAIInstance, workAIInstance, visionAIInstance,
|
|
187
258
|
aiService, humanize,
|
|
188
259
|
sessionManager, skillManager, rateLimiter, queueManager,
|
|
@@ -190,6 +261,7 @@ export default definePlugin({
|
|
|
190
261
|
cooldownManager: undefined as unknown as CooldownManager,
|
|
191
262
|
idleCheckManager: undefined as unknown as IdleCheckManager,
|
|
192
263
|
queueProcessor: undefined as unknown as QueueProcessor,
|
|
264
|
+
sessionTurnScheduler,
|
|
193
265
|
runWithRateLimitGuard,
|
|
194
266
|
buildHistoryMediaOptions,
|
|
195
267
|
getGroupHistoryMessages, getGroupInfoData, getHumanizeContexts,
|
|
@@ -209,12 +281,13 @@ export default definePlugin({
|
|
|
209
281
|
humanize.topicTracker.onMessage(groupSessionId),
|
|
210
282
|
]);
|
|
211
283
|
if (userMsg.groupId) {
|
|
284
|
+
const ttlMs = configProvider(userMsg.groupId).groupStructuredHistoryTtlMs;
|
|
212
285
|
groupStructuredHistory.append(
|
|
213
286
|
groupSessionId,
|
|
214
287
|
buildStructuredUserMessages([
|
|
215
288
|
buildStructuredUserInputFromTarget(userMsg as unknown as TargetMessage),
|
|
216
289
|
]),
|
|
217
|
-
|
|
290
|
+
ttlMs,
|
|
218
291
|
);
|
|
219
292
|
}
|
|
220
293
|
},
|
|
@@ -255,15 +328,17 @@ export default definePlugin({
|
|
|
255
328
|
ctx.logger.info("聊天插件加载成功");
|
|
256
329
|
|
|
257
330
|
return () => {
|
|
258
|
-
db.close();
|
|
259
|
-
rateLimiter.dispose();
|
|
260
|
-
clearInterval(cleanupInterval);
|
|
261
|
-
dbCleanup.stop();
|
|
262
|
-
cooldownManager.dispose();
|
|
263
331
|
idleCheckManager.dispose();
|
|
332
|
+
cooldownManager.dispose();
|
|
264
333
|
queueProcessor.dispose();
|
|
334
|
+
sessionTurnScheduler.dispose();
|
|
335
|
+
queueManager.dispose();
|
|
336
|
+
clearInterval(cleanupInterval);
|
|
337
|
+
dbCleanup.stop();
|
|
338
|
+
rateLimiter.dispose();
|
|
265
339
|
processingSet.clear();
|
|
266
340
|
pokeCooldowns.clear();
|
|
341
|
+
db.close();
|
|
267
342
|
ctx.logger.info("聊天插件已卸载");
|
|
268
343
|
};
|
|
269
344
|
},
|
package/manage/cooldown.ts
CHANGED
|
@@ -2,27 +2,24 @@ import type { MiokiContext } from "mioki";
|
|
|
2
2
|
import type { AIInstance } from "mioku";
|
|
3
3
|
import type { ChatConfig, TargetMessage } from "../types";
|
|
4
4
|
import type { ChatDatabase } from "../db";
|
|
5
|
-
import type { HumanizeEngine } from "../humanize";
|
|
5
|
+
import type { HumanizeEngine, ChatConfigProvider } from "../humanize";
|
|
6
6
|
import type { SkillSessionManager } from "./skill-session";
|
|
7
7
|
import type { GroupStructuredHistoryManager } from "./group-structured-history";
|
|
8
8
|
import { buildStructuredUserInputFromEvent } from "./group-structured-history";
|
|
9
|
-
import type { SessionManager } from "./session";
|
|
10
9
|
import type { RateLimiter } from "./rate-limiter";
|
|
11
|
-
import type { IdleCheckManager } from "./idle-check";
|
|
12
10
|
import type {
|
|
13
11
|
RunRateLimitGuard,
|
|
14
12
|
HistoryMediaOptions,
|
|
15
13
|
GetGroupHistoryMessages,
|
|
16
14
|
GetGroupInfoData,
|
|
17
15
|
GetHumanizeContexts,
|
|
18
|
-
SendAIResponse,
|
|
19
|
-
SaveBotMessages,
|
|
20
|
-
SendEmoji,
|
|
21
16
|
RunChat,
|
|
22
17
|
BuildToolContext,
|
|
23
18
|
BuildStructuredUserInput,
|
|
24
19
|
} from "./types";
|
|
25
20
|
import type { ChatPluginContext } from "../context";
|
|
21
|
+
import type { SessionTurnScheduler } from "./session-turn-scheduler";
|
|
22
|
+
import { finalizeChatTurn } from "../core/chat-turn";
|
|
26
23
|
import { getBotRole } from "../utils";
|
|
27
24
|
|
|
28
25
|
interface CooldownMessage {
|
|
@@ -39,18 +36,19 @@ export class CooldownManager {
|
|
|
39
36
|
private groupCooldownUntil = new Map<string, number>();
|
|
40
37
|
private groupCooldownMessages = new Map<string, CooldownMessage[]>();
|
|
41
38
|
private cooldownTimeoutIds = new Map<string, NodeJS.Timeout>();
|
|
39
|
+
private pluginCtx: ChatPluginContext;
|
|
40
|
+
private sessionTurnScheduler: SessionTurnScheduler;
|
|
42
41
|
|
|
43
42
|
private ctx: MiokiContext;
|
|
44
|
-
private
|
|
43
|
+
private configProvider: ChatConfigProvider;
|
|
44
|
+
private defaultConfig: ChatConfig;
|
|
45
45
|
private db: ChatDatabase;
|
|
46
46
|
private humanize: HumanizeEngine;
|
|
47
47
|
private aiInstance: AIInstance;
|
|
48
48
|
private aiService: import("mioku").AIService;
|
|
49
49
|
private skillManager: SkillSessionManager;
|
|
50
50
|
private groupStructuredHistory: GroupStructuredHistoryManager;
|
|
51
|
-
private sessionManager: SessionManager;
|
|
52
51
|
private rateLimiter: RateLimiter;
|
|
53
|
-
private idleCheckManager: IdleCheckManager;
|
|
54
52
|
private runWithRateLimitGuard: RunRateLimitGuard;
|
|
55
53
|
private buildHistoryMediaOptions: (
|
|
56
54
|
ai: AIInstance,
|
|
@@ -59,33 +57,28 @@ export class CooldownManager {
|
|
|
59
57
|
private getGroupHistoryMessages: GetGroupHistoryMessages;
|
|
60
58
|
private getGroupInfoData: GetGroupInfoData;
|
|
61
59
|
private getHumanizeContexts: GetHumanizeContexts;
|
|
62
|
-
private sendAIResponse: SendAIResponse;
|
|
63
|
-
private saveBotMessages: SaveBotMessages;
|
|
64
|
-
private sendEmoji: SendEmoji;
|
|
65
60
|
private runChat: RunChat;
|
|
66
61
|
private buildToolContext: BuildToolContext;
|
|
67
62
|
private buildStructuredUserInputFromEvent: BuildStructuredUserInput;
|
|
68
63
|
|
|
69
64
|
constructor(pluginCtx: ChatPluginContext) {
|
|
65
|
+
this.pluginCtx = pluginCtx;
|
|
66
|
+
this.sessionTurnScheduler = pluginCtx.sessionTurnScheduler;
|
|
70
67
|
this.ctx = pluginCtx.ctx;
|
|
71
|
-
this.
|
|
68
|
+
this.configProvider = pluginCtx.configProvider;
|
|
69
|
+
this.defaultConfig = pluginCtx.defaultConfig;
|
|
72
70
|
this.db = pluginCtx.db;
|
|
73
71
|
this.humanize = pluginCtx.humanize;
|
|
74
72
|
this.aiInstance = pluginCtx.aiInstance;
|
|
75
73
|
this.aiService = pluginCtx.aiService;
|
|
76
74
|
this.skillManager = pluginCtx.skillManager;
|
|
77
75
|
this.groupStructuredHistory = pluginCtx.groupStructuredHistory;
|
|
78
|
-
this.sessionManager = pluginCtx.sessionManager;
|
|
79
76
|
this.rateLimiter = pluginCtx.rateLimiter;
|
|
80
|
-
this.idleCheckManager = pluginCtx.idleCheckManager;
|
|
81
77
|
this.runWithRateLimitGuard = pluginCtx.runWithRateLimitGuard;
|
|
82
78
|
this.buildHistoryMediaOptions = pluginCtx.buildHistoryMediaOptions;
|
|
83
79
|
this.getGroupHistoryMessages = pluginCtx.getGroupHistoryMessages;
|
|
84
80
|
this.getGroupInfoData = pluginCtx.getGroupInfoData;
|
|
85
81
|
this.getHumanizeContexts = pluginCtx.getHumanizeContexts;
|
|
86
|
-
this.sendAIResponse = pluginCtx.sendAIResponse;
|
|
87
|
-
this.saveBotMessages = pluginCtx.saveBotMessages;
|
|
88
|
-
this.sendEmoji = pluginCtx.sendEmoji;
|
|
89
82
|
this.runChat = pluginCtx.runChat;
|
|
90
83
|
this.buildToolContext = pluginCtx.buildToolContext;
|
|
91
84
|
this.buildStructuredUserInputFromEvent = buildStructuredUserInputFromEvent;
|
|
@@ -99,47 +92,52 @@ export class CooldownManager {
|
|
|
99
92
|
const existingTimer = this.cooldownTimeoutIds.get(groupSessionId);
|
|
100
93
|
if (existingTimer) clearTimeout(existingTimer);
|
|
101
94
|
|
|
102
|
-
const
|
|
95
|
+
const cfg = this.configProvider(groupId);
|
|
96
|
+
const cooldownMs =
|
|
97
|
+
cfg.cooldownAfterReplyMs ??
|
|
98
|
+
this.defaultConfig.cooldownAfterReplyMs ??
|
|
99
|
+
20_000;
|
|
103
100
|
|
|
104
|
-
const timer = setTimeout(
|
|
101
|
+
const timer = setTimeout(() => {
|
|
102
|
+
if (this.cooldownTimeoutIds.get(groupSessionId) !== timer) return;
|
|
105
103
|
this.cooldownTimeoutIds.delete(groupSessionId);
|
|
104
|
+
this.groupCooldownUntil.delete(groupSessionId);
|
|
106
105
|
const collected = this.groupCooldownMessages.get(groupSessionId) || [];
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.groupCooldownUntil.delete(groupSessionId);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
106
|
+
this.groupCooldownMessages.delete(groupSessionId);
|
|
107
|
+
if (collected.length === 0) return;
|
|
112
108
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
109
|
+
const hasDirectAt = collected.some((message) => message.isDirectAt);
|
|
110
|
+
void this.sessionTurnScheduler
|
|
111
|
+
.run(
|
|
112
|
+
groupSessionId,
|
|
113
|
+
hasDirectAt ? "cooldown" : "cooldown-planner",
|
|
114
|
+
() =>
|
|
115
|
+
hasDirectAt
|
|
116
|
+
? this.processReviewMessages(
|
|
117
|
+
groupSessionId,
|
|
118
|
+
groupId,
|
|
119
|
+
collected,
|
|
120
|
+
selfId,
|
|
121
|
+
)
|
|
122
|
+
: this.processCooldownWithPlanner(
|
|
123
|
+
groupSessionId,
|
|
124
|
+
groupId,
|
|
125
|
+
collected,
|
|
126
|
+
selfId,
|
|
127
|
+
),
|
|
128
|
+
)
|
|
129
|
+
.catch((err) =>
|
|
130
|
+
this.ctx.logger.error(
|
|
131
|
+
`[Cooldown] Group ${groupId} processing failed: ${err}`,
|
|
132
|
+
),
|
|
133
133
|
);
|
|
134
|
-
} finally {
|
|
135
|
-
this.groupCooldownMessages.delete(groupSessionId);
|
|
136
|
-
this.groupCooldownUntil.delete(groupSessionId);
|
|
137
|
-
}
|
|
138
134
|
}, cooldownMs);
|
|
139
135
|
|
|
140
136
|
this.cooldownTimeoutIds.set(groupSessionId, timer);
|
|
141
137
|
this.groupCooldownUntil.set(groupSessionId, Date.now() + cooldownMs);
|
|
142
|
-
this.groupCooldownMessages.
|
|
138
|
+
if (!this.groupCooldownMessages.has(groupSessionId)) {
|
|
139
|
+
this.groupCooldownMessages.set(groupSessionId, []);
|
|
140
|
+
}
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
collectMessage(
|
|
@@ -196,17 +194,19 @@ export class CooldownManager {
|
|
|
196
194
|
timestamp: Date.now(),
|
|
197
195
|
};
|
|
198
196
|
|
|
197
|
+
const cfg = this.configProvider(groupId);
|
|
198
|
+
|
|
199
199
|
const { history } = await this.getGroupHistoryMessages(
|
|
200
200
|
groupId,
|
|
201
201
|
groupSessionId,
|
|
202
202
|
this.ctx,
|
|
203
|
-
|
|
203
|
+
cfg.historyCount,
|
|
204
204
|
this.db,
|
|
205
205
|
selfId,
|
|
206
|
-
this.buildHistoryMediaOptions(this.aiInstance,
|
|
206
|
+
this.buildHistoryMediaOptions(this.aiInstance, cfg),
|
|
207
207
|
);
|
|
208
208
|
const botNickname =
|
|
209
|
-
|
|
209
|
+
cfg.nicknames[0] || this.ctx.pickBot(selfId).nickname || "Bot";
|
|
210
210
|
const botRole = await getBotRole(groupId, this.ctx, selfId);
|
|
211
211
|
const { groupName, memberCount } = await this.getGroupInfoData(
|
|
212
212
|
this.ctx,
|
|
@@ -220,7 +220,7 @@ export class CooldownManager {
|
|
|
220
220
|
groupSessionId,
|
|
221
221
|
groupId,
|
|
222
222
|
userId: targetMessage.userId,
|
|
223
|
-
config:
|
|
223
|
+
config: cfg,
|
|
224
224
|
aiService: this.aiService,
|
|
225
225
|
db: this.db,
|
|
226
226
|
botRole,
|
|
@@ -245,7 +245,7 @@ export class CooldownManager {
|
|
|
245
245
|
history,
|
|
246
246
|
targetMessage,
|
|
247
247
|
{
|
|
248
|
-
config:
|
|
248
|
+
config: cfg,
|
|
249
249
|
groupName,
|
|
250
250
|
memberCount,
|
|
251
251
|
botNickname,
|
|
@@ -266,7 +266,7 @@ export class CooldownManager {
|
|
|
266
266
|
this.skillManager,
|
|
267
267
|
{
|
|
268
268
|
manager: this.groupStructuredHistory,
|
|
269
|
-
ttlMs:
|
|
269
|
+
ttlMs: cfg.groupStructuredHistoryTtlMs,
|
|
270
270
|
currentUserInputs: collected.map((msg) =>
|
|
271
271
|
this.buildStructuredUserInputFromEvent(
|
|
272
272
|
msg.event,
|
|
@@ -280,36 +280,18 @@ export class CooldownManager {
|
|
|
280
280
|
);
|
|
281
281
|
if (!result) return;
|
|
282
282
|
|
|
283
|
-
await this.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
messages: result.messages,
|
|
288
|
-
config: this.cfg,
|
|
289
|
-
sentIndices: toolCtx.sentMessageIndices,
|
|
290
|
-
},
|
|
291
|
-
selfId,
|
|
292
|
-
);
|
|
293
|
-
await this.sendEmoji(this.ctx, groupId, result.emojiPath, selfId);
|
|
294
|
-
|
|
295
|
-
const now = Date.now();
|
|
296
|
-
this.saveBotMessages(
|
|
283
|
+
await finalizeChatTurn(this.pluginCtx, {
|
|
284
|
+
event: firstMsg.event,
|
|
285
|
+
cfg,
|
|
286
|
+
result,
|
|
297
287
|
groupId,
|
|
298
288
|
groupSessionId,
|
|
299
|
-
|
|
300
|
-
now,
|
|
301
|
-
this.cfg,
|
|
302
|
-
this.db,
|
|
303
|
-
this.ctx,
|
|
304
|
-
selfId,
|
|
305
|
-
);
|
|
306
|
-
this.idleCheckManager.recordBotMessages(
|
|
307
|
-
groupSessionId,
|
|
308
|
-
result.messages.length,
|
|
289
|
+
userId: targetMessage.userId,
|
|
309
290
|
selfId,
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
291
|
+
toolCtx,
|
|
292
|
+
send: true,
|
|
293
|
+
isLive: true,
|
|
294
|
+
});
|
|
313
295
|
}
|
|
314
296
|
|
|
315
297
|
private async processCooldownWithPlanner(
|
|
@@ -321,17 +303,19 @@ export class CooldownManager {
|
|
|
321
303
|
const mergedContent = collected.map((m) => m.content).join("\n");
|
|
322
304
|
const firstMsg = collected[0];
|
|
323
305
|
|
|
306
|
+
const cfg = this.configProvider(groupId);
|
|
307
|
+
|
|
324
308
|
const { history } = await this.getGroupHistoryMessages(
|
|
325
309
|
groupId,
|
|
326
310
|
groupSessionId,
|
|
327
311
|
this.ctx,
|
|
328
|
-
|
|
312
|
+
cfg.historyCount,
|
|
329
313
|
this.db,
|
|
330
314
|
selfId,
|
|
331
|
-
this.buildHistoryMediaOptions(this.aiInstance,
|
|
315
|
+
this.buildHistoryMediaOptions(this.aiInstance, cfg),
|
|
332
316
|
);
|
|
333
317
|
const botNickname =
|
|
334
|
-
|
|
318
|
+
cfg.nicknames[0] || this.ctx.pickBot(selfId).nickname || "Bot";
|
|
335
319
|
|
|
336
320
|
const planResult = await this.humanize.actionPlanner.plan(
|
|
337
321
|
groupSessionId,
|
|
@@ -362,7 +346,7 @@ export class CooldownManager {
|
|
|
362
346
|
groupSessionId,
|
|
363
347
|
groupId,
|
|
364
348
|
userId: targetMessage.userId,
|
|
365
|
-
config:
|
|
349
|
+
config: cfg,
|
|
366
350
|
aiService: this.aiService,
|
|
367
351
|
db: this.db,
|
|
368
352
|
botRole,
|
|
@@ -392,7 +376,7 @@ export class CooldownManager {
|
|
|
392
376
|
history,
|
|
393
377
|
targetMessage,
|
|
394
378
|
{
|
|
395
|
-
config:
|
|
379
|
+
config: cfg,
|
|
396
380
|
groupName,
|
|
397
381
|
memberCount,
|
|
398
382
|
botNickname,
|
|
@@ -418,7 +402,7 @@ export class CooldownManager {
|
|
|
418
402
|
this.skillManager,
|
|
419
403
|
{
|
|
420
404
|
manager: this.groupStructuredHistory,
|
|
421
|
-
ttlMs:
|
|
405
|
+
ttlMs: cfg.groupStructuredHistoryTtlMs,
|
|
422
406
|
currentUserInputs: collected.map((msg) =>
|
|
423
407
|
this.buildStructuredUserInputFromEvent(
|
|
424
408
|
msg.event,
|
|
@@ -437,34 +421,17 @@ export class CooldownManager {
|
|
|
437
421
|
return;
|
|
438
422
|
}
|
|
439
423
|
|
|
440
|
-
await this.
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
messages: result.messages,
|
|
445
|
-
config: this.cfg,
|
|
446
|
-
sentIndices: toolCtx.sentMessageIndices,
|
|
447
|
-
},
|
|
448
|
-
selfId,
|
|
449
|
-
);
|
|
450
|
-
await this.sendEmoji(this.ctx, groupId, result.emojiPath, selfId);
|
|
451
|
-
const now = Date.now();
|
|
452
|
-
this.saveBotMessages(
|
|
424
|
+
await finalizeChatTurn(this.pluginCtx, {
|
|
425
|
+
event: firstMsg.event,
|
|
426
|
+
cfg,
|
|
427
|
+
result,
|
|
453
428
|
groupId,
|
|
454
429
|
groupSessionId,
|
|
455
|
-
|
|
456
|
-
now,
|
|
457
|
-
this.cfg,
|
|
458
|
-
this.db,
|
|
459
|
-
this.ctx,
|
|
460
|
-
selfId,
|
|
461
|
-
);
|
|
462
|
-
this.idleCheckManager.recordBotMessages(
|
|
463
|
-
groupSessionId,
|
|
464
|
-
result.messages.length,
|
|
430
|
+
userId: targetMessage.userId,
|
|
465
431
|
selfId,
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
432
|
+
toolCtx,
|
|
433
|
+
send: true,
|
|
434
|
+
isLive: true,
|
|
435
|
+
});
|
|
469
436
|
}
|
|
470
|
-
}
|
|
437
|
+
}
|