mioku-plugin-chat 2.0.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/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "mioku-plugin-chat",
3
+ "version": "2.0.0",
4
+ "description": "AI 智能聊天插件",
5
+ "main": "index.ts",
6
+ "type": "module",
7
+ "keywords": [
8
+ "mioku"
9
+ ],
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/mioku-lab/mioku.git"
13
+ },
14
+ "mioku": {
15
+ "services": [
16
+ "ai",
17
+ "config",
18
+ "help",
19
+ "screenshot"
20
+ ],
21
+ "help": {
22
+ "title": "AI 聊天",
23
+ "description": "智能 AI 聊天插件",
24
+ "commands": [
25
+ {
26
+ "cmd": "/重置会话",
27
+ "desc": "重置自己的AI聊天记录",
28
+ "role": "member"
29
+ },
30
+ {
31
+ "cmd": "/重置群会话",
32
+ "desc": "重置当前群的AI聊天记录",
33
+ "role": "admin"
34
+ }
35
+ ]
36
+ }
37
+ },
38
+ "dependencies": {
39
+ "openai": "^4.0.0",
40
+ "sharp": "^0.34.5"
41
+ },
42
+ "devDependencies": {
43
+ "@types/bun": "^1.3.14",
44
+ "mioki": "^0.16.0",
45
+ "mioku": "workspace:*"
46
+ },
47
+ "peerDependencies": {
48
+ "mioku": "^0.8.0",
49
+ "mioki": "^0.16.0"
50
+ }
51
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": true
5
+ },
6
+ "include": ["**/*.ts"]
7
+ }
package/types.ts ADDED
@@ -0,0 +1,381 @@
1
+ import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
2
+ import type { MiokiContext } from "mioki";
3
+ import type { AITool, AIService, SkillPermissionRole } from "mioku";
4
+ import type { ChatDatabase } from "./db";
5
+
6
+ /**
7
+ * 人格状态配置
8
+ */
9
+ export interface PersonalityConfig {
10
+ // 状态列表
11
+ states: string[];
12
+ // 切换到其他状态的概率 (0-1)
13
+ stateProbability: number;
14
+ }
15
+
16
+ /**
17
+ * 回复风格配置
18
+ */
19
+ export interface ReplyStyleConfig {
20
+ // 默认回复风格
21
+ baseStyle: string;
22
+ // 特殊回复风格
23
+ multipleStyles: string[];
24
+ // 使用特殊风格的概率 (0-1)
25
+ multipleProbability: number;
26
+ }
27
+
28
+ /**
29
+ * 记忆检索配置
30
+ */
31
+ export interface MemoryConfig {
32
+ enabled: boolean;
33
+ // 回忆时拉取的群聊历史条数(通过 message_id 分页)
34
+ groupHistoryLimit: number;
35
+ // 回忆时每个用户历史的默认条数
36
+ userHistoryLimit: number;
37
+ }
38
+
39
+ /**
40
+ * 话题跟踪配置
41
+ */
42
+ export interface TopicConfig {
43
+ enabled: boolean;
44
+ // 话题窗口长度(小时),同时也是每个群的检查周期
45
+ windowHours: number;
46
+ // 在提示词中回填多少个历史窗口
47
+ historyWindowCount: number;
48
+ }
49
+
50
+ /**
51
+ * 动作规划器配置
52
+ */
53
+ export interface PlannerConfig {
54
+ enabled: boolean;
55
+ // 群聊空闲时间阈值(毫秒)
56
+ idleThresholdMs: number;
57
+ // 群聊记录保底消息数量
58
+ idleMessageCount: number;
59
+ // 空闲检查的 bot ID 列表
60
+ idleCheckBotIds: number[];
61
+ }
62
+
63
+
64
+ /**
65
+ * 表情包系统配置
66
+ */
67
+ export interface EmojiConfig {
68
+ enabled: boolean;
69
+ // 允许的表情包角色
70
+ characters: string[];
71
+ // 使用AI选择表情包发送
72
+ useAISelection: boolean;
73
+ }
74
+
75
+ /**
76
+ * 表达学习配置
77
+ */
78
+ export interface ExpressionConfig {
79
+ enabled: boolean;
80
+ // 单个用户累积多少条消息后触发表达学习
81
+ learnAfterMessages: number;
82
+ // 单个用户最多保留/注入的表达习惯条数
83
+ sampleSize: number;
84
+ }
85
+
86
+ /**
87
+ * 动态延迟配置
88
+ * 根据互动人数动态调整回复延迟
89
+ */
90
+ export interface DynamicDelayConfig {
91
+ enabled: boolean;
92
+ // 互动窗口 在这个区间内统计群聊活跃程度
93
+ interactionWindowMs: number;
94
+ // 每个人与bot交互后增加的基础延迟
95
+ baseDelayMs: number;
96
+ // 延迟最大上限
97
+ maxDelayMs: number;
98
+ }
99
+
100
+ /**
101
+ * SearXNG 网页搜索配置
102
+ */
103
+ export interface SearxngConfig {
104
+ enabled: boolean;
105
+ // 服务器URL
106
+ baseUrl: string;
107
+ // 超时
108
+ timeoutMs: number;
109
+ // 获取的搜索结果的默认上限
110
+ defaultLimit: number;
111
+ // 最大上限
112
+ maxLimit: number;
113
+ }
114
+
115
+ /**
116
+ * 网页阅读工具配置
117
+ */
118
+ export interface WebReaderConfig {
119
+ enabled: boolean;
120
+ // 是否使用工作模型精简网页结果
121
+ useWorkingModel: boolean;
122
+ // 超时
123
+ timeoutMs: number;
124
+ // 最大网页字节数
125
+ maxHtmlBytes: number;
126
+ // 最大字符数
127
+ maxExtractedChars: number;
128
+ // 浏览器渲染超时
129
+ browserTimeoutMs: number;
130
+ // 允许的网页格式
131
+ allowedContentTypes: string[];
132
+ }
133
+
134
+ /**
135
+ * 语音消息配置
136
+ */
137
+ export interface AudioConfig {
138
+ enabled: boolean;
139
+ // 服务器URL
140
+ baseUrl: string;
141
+ // 密钥
142
+ apiKey: string;
143
+ timeoutMs: number;
144
+ }
145
+
146
+ export interface AIRequestLimitConfig {
147
+ userRpm: number;
148
+ groupRpm: number;
149
+ windowMs: number;
150
+ }
151
+
152
+ /**
153
+ * 聊天插件配置
154
+ */
155
+ export interface ChatConfig {
156
+ apiUrl: string;
157
+ apiKey: string;
158
+ model: string;
159
+ workingModel: string;
160
+ multimodalWorkingModel: string;
161
+ isMultimodal: boolean;
162
+ nicknames: string[];
163
+ persona: string;
164
+ maxContextTokens: number;
165
+ temperature: number;
166
+ searxng: SearxngConfig;
167
+ webReader: WebReaderConfig;
168
+ audio: AudioConfig;
169
+ historyCount: number;
170
+ blacklistGroups: number[];
171
+ whitelistGroups: number[];
172
+ mediaAnalysisBlacklistUsers: number[];
173
+ maxSessions: number;
174
+ maxIterations: number;
175
+ enableExternalSkills: boolean;
176
+ allowedExternalSkills: string[];
177
+ stream: boolean;
178
+ enableTypingDelay: boolean;
179
+ typingDelayMaxTotalMs: number;
180
+ enableMarkdownScreenshot: boolean;
181
+ debug: boolean;
182
+ outputLengthConstraintStrength: "low" | "medium" | "high";
183
+ toolCallConstraintStrength: "low" | "medium" | "high";
184
+ emojiUsageConstraintStrength: "low" | "medium" | "high";
185
+ audioUsageConstraintStrength: "low" | "medium" | "high";
186
+ markdownUsageConstraintStrength: "low" | "medium" | "high";
187
+ groupStructuredHistoryTtlMs: number;
188
+ cooldownAfterReplyMs: number;
189
+ aiRequestLimits: AIRequestLimitConfig;
190
+ dynamicDelay: DynamicDelayConfig;
191
+ personality: PersonalityConfig;
192
+ replyStyle: ReplyStyleConfig;
193
+ memory: MemoryConfig;
194
+ topic: TopicConfig;
195
+ planner: PlannerConfig;
196
+ emoji: EmojiConfig;
197
+ expression: ExpressionConfig;
198
+ }
199
+
200
+ /**
201
+ * 会话类型
202
+ */
203
+ export type SessionType = "group" | "personal";
204
+
205
+ /**
206
+ * 会话元数据
207
+ */
208
+ export interface SessionMeta {
209
+ id: string; // "group:{group_id}" 或 "personal:{user_id}"
210
+ type: SessionType;
211
+ targetId: number; // group_id 或 user_id
212
+ createdAt: number;
213
+ updatedAt: number;
214
+ compressedContext: string | null;
215
+ }
216
+
217
+ /**
218
+ * 聊天消息记录
219
+ */
220
+ export interface ChatMessage {
221
+ id?: number;
222
+ sessionId: string;
223
+ role: "user" | "assistant" | "system";
224
+ content: string; // 存储时统一为字符串
225
+ userId?: number;
226
+ userName?: string;
227
+ userRole?: string; // "owner" | "admin" | "member"
228
+ userTitle?: string;
229
+ groupId?: number;
230
+ groupName?: string;
231
+ timestamp: number;
232
+ messageId?: number; // QQ message_id
233
+ }
234
+
235
+ /**
236
+ * 触发消息
237
+ */
238
+ export interface TargetMessage {
239
+ userName: string;
240
+ userId: number;
241
+ userRole: string;
242
+ userTitle?: string;
243
+ content: string;
244
+ messageId?: number;
245
+ timestamp: number;
246
+ }
247
+
248
+ /**
249
+ * 技能会话(per group session)
250
+ */
251
+ export interface SkillSession {
252
+ skillName: string;
253
+ tools: Map<string, AITool>;
254
+ loadedAt: number;
255
+ expiresAt: number; // loadedAt + 1h
256
+ }
257
+
258
+ /**
259
+ * 工具上下文
260
+ */
261
+ export interface ToolContext {
262
+ ctx: MiokiContext;
263
+ event: any;
264
+ sessionId: string;
265
+ groupId?: number;
266
+ userId: number;
267
+ triggerSkillRole: SkillPermissionRole;
268
+ config: ChatConfig;
269
+ aiService: AIService;
270
+ db: ChatDatabase;
271
+ botRole: "owner" | "admin" | "member";
272
+ /**
273
+ * 当 AI 返回文本内容时立即调用
274
+ * 回调接收文本内容、消息索引、总消息数
275
+ */
276
+ onTextContent?: (
277
+ text: string,
278
+ messageIndex: number,
279
+ totalMessages: number,
280
+ ) => void | Promise<void>;
281
+ /**
282
+ * 已通过 onTextContent 回调发送的消息索引集合
283
+ */
284
+ sentMessageIndices?: Set<number>;
285
+ /**
286
+ * 待附加到下一轮 AI 请求的图片 URL
287
+ */
288
+ pendingImageUrls?: string[];
289
+ }
290
+
291
+ /**
292
+ * 聊天结果
293
+ */
294
+ export interface ChatResult {
295
+ messages: string[];
296
+ pendingAt: number[];
297
+ pendingPoke: number[];
298
+ pendingQuote?: number;
299
+ toolCalls: { name: string; args: any; result: any }[];
300
+ emojiPath?: string | null;
301
+ protocolMessages?: ChatCompletionMessageParam[];
302
+ }
303
+
304
+ /**
305
+ * 话题记录
306
+ */
307
+ export interface TopicRecord {
308
+ id?: number;
309
+ sessionId: string;
310
+ title: string;
311
+ keywords: string; // JSON array
312
+ summary: string;
313
+ messageCount: number;
314
+ windowStartAt?: number;
315
+ windowEndAt?: number;
316
+ createdAt: number;
317
+ updatedAt: number;
318
+ }
319
+
320
+ /**
321
+ * 表达习惯记录
322
+ */
323
+ export interface ExpressionRecord {
324
+ id?: number;
325
+ sessionId: string;
326
+ userId: number;
327
+ userName: string;
328
+ situation: string; // 使用场景
329
+ style: string; // 表达风格
330
+ example: string; // 原始示例
331
+ createdAt: number;
332
+ }
333
+
334
+ /**
335
+ * 表情包注册记录
336
+ */
337
+ export interface EmojiRecord {
338
+ id?: number;
339
+ fileName: string;
340
+ description: string; // AI 生成的描述
341
+ emotion: string; // 情感标签
342
+ usageCount: number;
343
+ createdAt: number;
344
+ }
345
+
346
+ /**
347
+ * 图片记录
348
+ */
349
+ export interface ImageRecord {
350
+ id?: number;
351
+ hash: string; // 图片哈希
352
+ url: string; // 原始 URL
353
+ type: "meme" | "image"; // 图片类型
354
+ description: string; // AI 生成的简要描述
355
+ emotion?: string; // 情感标签(仅表情包)
356
+ character?: string; // 角色名称(仅表情包)
357
+ filePath?: string; // 本地文件路径(仅表情包)
358
+ createdAt: number;
359
+ }
360
+
361
+ export type MediaSummaryKind = "video" | "forward" | "card" | "notice";
362
+
363
+ export interface MediaSummaryRecord {
364
+ id?: number;
365
+ key: string;
366
+ kind: MediaSummaryKind;
367
+ source: string;
368
+ summary: string;
369
+ createdAt: number;
370
+ }
371
+
372
+ /**
373
+ * 动作规划结果
374
+ */
375
+ export type PlannerAction = "reply" | "wait" | "complete";
376
+
377
+ export interface PlannerResult {
378
+ action: PlannerAction;
379
+ reason: string;
380
+ waitMs?: number; // action=wait 时的等待时间
381
+ }
package/utils/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export {
2
+ shouldTrigger,
3
+ isQuotingBot,
4
+ isGroupAllowed,
5
+ extractContent,
6
+ getBotRole,
7
+ getQuotedContent,
8
+ getGroupHistory,
9
+ } from "./message";