mioku-plugin-chat 2.6.0 → 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/personalization.ts +1 -1
- package/context.ts +2 -0
- package/core/base.ts +1 -1
- package/core/chat-engine.ts +18 -7
- package/core/chat-turn.ts +26 -9
- package/core/media/image-analyzer.ts +63 -397
- package/core/prompt.ts +11 -20
- package/db.ts +8 -12
- package/handlers/idle-debug.ts +96 -97
- package/handlers/message.ts +35 -34
- package/handlers/poke.ts +102 -124
- package/humanize/emoji-agent.ts +208 -332
- package/humanize/index.ts +2 -3
- package/index.ts +32 -44
- package/manage/cooldown.ts +60 -100
- package/manage/idle-check.ts +163 -70
- package/manage/queue-processor.ts +73 -30
- package/manage/session-turn-scheduler.ts +130 -0
- package/package.json +1 -1
- package/runtime/chat-runtime.ts +14 -2
- package/types.ts +2 -19
- package/utils/config.ts +57 -0
- package/utils/message.ts +4 -7
- package/utils/queue.ts +5 -0
package/types.ts
CHANGED
|
@@ -65,10 +65,8 @@ export interface PlannerConfig {
|
|
|
65
65
|
*/
|
|
66
66
|
export interface EmojiConfig {
|
|
67
67
|
enabled: boolean;
|
|
68
|
-
// 允许的表情包角色
|
|
69
68
|
characters: string[];
|
|
70
|
-
|
|
71
|
-
useAISelection: boolean;
|
|
69
|
+
stickers: string[];
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
/**
|
|
@@ -376,18 +374,6 @@ export interface ExpressionRecord {
|
|
|
376
374
|
createdAt: number;
|
|
377
375
|
}
|
|
378
376
|
|
|
379
|
-
/**
|
|
380
|
-
* 表情包注册记录
|
|
381
|
-
*/
|
|
382
|
-
export interface EmojiRecord {
|
|
383
|
-
id?: number;
|
|
384
|
-
fileName: string;
|
|
385
|
-
description: string; // AI 生成的描述
|
|
386
|
-
emotion: string; // 情感标签
|
|
387
|
-
usageCount: number;
|
|
388
|
-
createdAt: number;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
377
|
/**
|
|
392
378
|
* 图片记录
|
|
393
379
|
*/
|
|
@@ -395,11 +381,8 @@ export interface ImageRecord {
|
|
|
395
381
|
id?: number;
|
|
396
382
|
hash: string; // 图片哈希
|
|
397
383
|
url: string; // 原始 URL
|
|
398
|
-
type: "
|
|
384
|
+
type: "image";
|
|
399
385
|
description: string; // AI 生成的简要描述
|
|
400
|
-
emotion?: string; // 情感标签(仅表情包)
|
|
401
|
-
character?: string; // 角色名称(仅表情包)
|
|
402
|
-
filePath?: string; // 本地文件路径(仅表情包)
|
|
403
386
|
createdAt: number;
|
|
404
387
|
}
|
|
405
388
|
|
package/utils/config.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
function isConfigObject(value: unknown): value is Record<string, any> {
|
|
2
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function mergeChatConfig<T extends Record<string, any>>(
|
|
6
|
+
defaults: T,
|
|
7
|
+
overrides: Record<string, any>,
|
|
8
|
+
): T {
|
|
9
|
+
const result: Record<string, any> = {};
|
|
10
|
+
|
|
11
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
12
|
+
if (isConfigObject(value)) {
|
|
13
|
+
result[key] = mergeChatConfig(value, {});
|
|
14
|
+
} else if (Array.isArray(value)) {
|
|
15
|
+
result[key] = [...value];
|
|
16
|
+
} else {
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
22
|
+
if (value === undefined || value === null) continue;
|
|
23
|
+
if (isConfigObject(value)) {
|
|
24
|
+
const baseValue = isConfigObject(result[key]) ? result[key] : {};
|
|
25
|
+
result[key] = mergeChatConfig(baseValue, value);
|
|
26
|
+
} else if (Array.isArray(value)) {
|
|
27
|
+
result[key] = [...value];
|
|
28
|
+
} else {
|
|
29
|
+
result[key] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return result as T;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function normalizeIdList(input: unknown): number[] {
|
|
37
|
+
if (!Array.isArray(input)) return [];
|
|
38
|
+
return Array.from(
|
|
39
|
+
new Set(
|
|
40
|
+
input
|
|
41
|
+
.map((item) => Math.floor(Number(item)))
|
|
42
|
+
.filter((id) => Number.isFinite(id) && id > 0),
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function normalizeMediaAnalysisBlacklist(
|
|
48
|
+
config: Record<string, any>,
|
|
49
|
+
): number[] {
|
|
50
|
+
const current = config.mediaAnalysisBlacklistUsers;
|
|
51
|
+
const legacy = config.imageAnalysisBlacklistUsers;
|
|
52
|
+
const source =
|
|
53
|
+
legacy !== undefined && Array.isArray(current) && current.length === 0
|
|
54
|
+
? legacy
|
|
55
|
+
: (current ?? legacy);
|
|
56
|
+
return normalizeIdList(source);
|
|
57
|
+
}
|
package/utils/message.ts
CHANGED
|
@@ -308,12 +308,12 @@ async function getImageTagWithHashCache(
|
|
|
308
308
|
ctx: HistoryFormatContext,
|
|
309
309
|
): Promise<string> {
|
|
310
310
|
const exact = db.getImageByUrl?.(imageUrl);
|
|
311
|
-
if (exact) return `[
|
|
311
|
+
if (exact) return `[image:${exact.description}]`;
|
|
312
312
|
|
|
313
313
|
const normalized = normalizeImageUrl(imageUrl);
|
|
314
314
|
if (normalized && normalized !== imageUrl) {
|
|
315
315
|
const hit = db.getImageByUrl?.(normalized);
|
|
316
|
-
if (hit) return `[
|
|
316
|
+
if (hit) return `[image:${hit.description}]`;
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
let hash = ctx.hashLookupCache.get(`hash:${imageUrl}`);
|
|
@@ -329,17 +329,14 @@ async function getImageTagWithHashCache(
|
|
|
329
329
|
db.saveImage?.({
|
|
330
330
|
hash: byHash.hash,
|
|
331
331
|
url: normalized || imageUrl,
|
|
332
|
-
type:
|
|
332
|
+
type: "image",
|
|
333
333
|
description: byHash.description,
|
|
334
|
-
emotion: byHash.emotion,
|
|
335
|
-
character: byHash.character,
|
|
336
|
-
filePath: byHash.filePath,
|
|
337
334
|
createdAt: byHash.createdAt,
|
|
338
335
|
});
|
|
339
336
|
} catch {
|
|
340
337
|
// best-effort URL caching for next call
|
|
341
338
|
}
|
|
342
|
-
return `[
|
|
339
|
+
return `[image:${byHash.description}]`;
|
|
343
340
|
}
|
|
344
341
|
|
|
345
342
|
return "[image]";
|
package/utils/queue.ts
CHANGED