@zhin.js/core 1.0.57 → 1.1.2

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.
Files changed (126) hide show
  1. package/lib/adapter.d.ts +1 -26
  2. package/lib/adapter.d.ts.map +1 -1
  3. package/lib/adapter.js +20 -117
  4. package/lib/adapter.js.map +1 -1
  5. package/lib/ai/index.d.ts +2 -0
  6. package/lib/ai/index.d.ts.map +1 -1
  7. package/lib/ai/index.js +1 -0
  8. package/lib/ai/index.js.map +1 -1
  9. package/lib/built/adapter-process.d.ts +0 -4
  10. package/lib/built/adapter-process.d.ts.map +1 -1
  11. package/lib/built/adapter-process.js +0 -95
  12. package/lib/built/adapter-process.js.map +1 -1
  13. package/lib/built/agent-preset.d.ts +2 -0
  14. package/lib/built/agent-preset.d.ts.map +1 -1
  15. package/lib/built/agent-preset.js +4 -0
  16. package/lib/built/agent-preset.js.map +1 -1
  17. package/lib/built/command.d.ts +4 -0
  18. package/lib/built/command.d.ts.map +1 -1
  19. package/lib/built/command.js +6 -0
  20. package/lib/built/command.js.map +1 -1
  21. package/lib/built/component.d.ts.map +1 -1
  22. package/lib/built/component.js +1 -0
  23. package/lib/built/component.js.map +1 -1
  24. package/lib/built/dispatcher.d.ts.map +1 -1
  25. package/lib/built/dispatcher.js +0 -13
  26. package/lib/built/dispatcher.js.map +1 -1
  27. package/lib/built/message-filter.d.ts +2 -0
  28. package/lib/built/message-filter.d.ts.map +1 -1
  29. package/lib/built/message-filter.js +5 -0
  30. package/lib/built/message-filter.js.map +1 -1
  31. package/lib/built/skill.d.ts +11 -0
  32. package/lib/built/skill.d.ts.map +1 -1
  33. package/lib/built/skill.js +14 -0
  34. package/lib/built/skill.js.map +1 -1
  35. package/lib/built/tool.d.ts +11 -44
  36. package/lib/built/tool.d.ts.map +1 -1
  37. package/lib/built/tool.js +14 -353
  38. package/lib/built/tool.js.map +1 -1
  39. package/lib/plugin.d.ts +1 -25
  40. package/lib/plugin.d.ts.map +1 -1
  41. package/lib/plugin.js +1 -77
  42. package/lib/plugin.js.map +1 -1
  43. package/lib/types.d.ts +0 -25
  44. package/lib/types.d.ts.map +1 -1
  45. package/package.json +10 -7
  46. package/CHANGELOG.md +0 -538
  47. package/REFACTORING_COMPLETE.md +0 -178
  48. package/REFACTORING_STATUS.md +0 -263
  49. package/src/adapter.ts +0 -275
  50. package/src/ai/index.ts +0 -52
  51. package/src/ai/providers/anthropic.ts +0 -379
  52. package/src/ai/providers/base.ts +0 -175
  53. package/src/ai/providers/index.ts +0 -13
  54. package/src/ai/providers/ollama.ts +0 -302
  55. package/src/ai/providers/openai.ts +0 -174
  56. package/src/ai/types.ts +0 -348
  57. package/src/bot.ts +0 -37
  58. package/src/built/adapter-process.ts +0 -177
  59. package/src/built/agent-preset.ts +0 -136
  60. package/src/built/ai-trigger.ts +0 -259
  61. package/src/built/command.ts +0 -108
  62. package/src/built/common-adapter-tools.ts +0 -242
  63. package/src/built/component.ts +0 -130
  64. package/src/built/config.ts +0 -335
  65. package/src/built/cron.ts +0 -156
  66. package/src/built/database.ts +0 -134
  67. package/src/built/dispatcher.ts +0 -496
  68. package/src/built/login-assist.ts +0 -131
  69. package/src/built/message-filter.ts +0 -390
  70. package/src/built/permission.ts +0 -151
  71. package/src/built/schema-feature.ts +0 -190
  72. package/src/built/skill.ts +0 -221
  73. package/src/built/tool.ts +0 -948
  74. package/src/command.ts +0 -87
  75. package/src/component.ts +0 -565
  76. package/src/cron.ts +0 -4
  77. package/src/errors.ts +0 -46
  78. package/src/feature.ts +0 -7
  79. package/src/index.ts +0 -53
  80. package/src/jsx-dev-runtime.ts +0 -2
  81. package/src/jsx-runtime.ts +0 -12
  82. package/src/jsx.ts +0 -135
  83. package/src/message.ts +0 -48
  84. package/src/models/system-log.ts +0 -20
  85. package/src/models/user.ts +0 -15
  86. package/src/notice.ts +0 -98
  87. package/src/plugin.ts +0 -896
  88. package/src/prompt.ts +0 -293
  89. package/src/request.ts +0 -95
  90. package/src/scheduler/index.ts +0 -19
  91. package/src/scheduler/scheduler.ts +0 -372
  92. package/src/scheduler/types.ts +0 -74
  93. package/src/tool-zod.ts +0 -115
  94. package/src/types-generator.ts +0 -78
  95. package/src/types.ts +0 -505
  96. package/src/utils.ts +0 -227
  97. package/tests/adapter.test.ts +0 -638
  98. package/tests/ai/ai-trigger.test.ts +0 -368
  99. package/tests/ai/providers.integration.test.ts +0 -227
  100. package/tests/ai/setup.ts +0 -308
  101. package/tests/ai/tool.test.ts +0 -800
  102. package/tests/bot.test.ts +0 -151
  103. package/tests/command.test.ts +0 -737
  104. package/tests/component-new.test.ts +0 -361
  105. package/tests/config.test.ts +0 -372
  106. package/tests/cron.test.ts +0 -82
  107. package/tests/dispatcher.test.ts +0 -293
  108. package/tests/errors.test.ts +0 -21
  109. package/tests/expression-evaluation.test.ts +0 -258
  110. package/tests/features-builtin.test.ts +0 -191
  111. package/tests/jsx-runtime.test.ts +0 -45
  112. package/tests/jsx.test.ts +0 -319
  113. package/tests/message-filter.test.ts +0 -566
  114. package/tests/message.test.ts +0 -402
  115. package/tests/notice.test.ts +0 -198
  116. package/tests/plugin.test.ts +0 -779
  117. package/tests/prompt.test.ts +0 -78
  118. package/tests/redos-protection.test.ts +0 -198
  119. package/tests/request.test.ts +0 -221
  120. package/tests/schema.test.ts +0 -248
  121. package/tests/skill-feature.test.ts +0 -179
  122. package/tests/test-utils.ts +0 -59
  123. package/tests/tool-feature.test.ts +0 -254
  124. package/tests/types.test.ts +0 -162
  125. package/tests/utils.test.ts +0 -135
  126. package/tsconfig.json +0 -24
@@ -1,259 +0,0 @@
1
- /**
2
- * AI Trigger 工具函数
3
- * 提供 AI 触发相关的工具函数,可在插件中直接使用
4
- *
5
- * 触发方式:
6
- * 1. @机器人 - 在群聊中 @ 机器人触发
7
- * 2. 前缀触发 - 使用配置的前缀(如 # 或 AI:)
8
- * 3. 私聊直接对话 - 私聊时直接对话
9
- * 4. 关键词触发 - 包含特定关键词时触发
10
- */
11
-
12
- import { Message } from "../message.js";
13
- import type {
14
- MessageElement,
15
- ToolScope,
16
- ToolPermissionLevel,
17
- MaybePromise,
18
- } from "../types.js";
19
- import { segment } from "../utils.js";
20
-
21
- // ============================================================================
22
- // 类型定义
23
- // ============================================================================
24
-
25
- /**
26
- * AI 触发配置
27
- */
28
- export interface AITriggerConfig {
29
- /** 是否启用(默认 true) */
30
- enabled?: boolean;
31
-
32
- /** 触发前缀列表(默认 ['#', 'AI:']) */
33
- prefixes?: string[];
34
-
35
- /** 是否响应 @ 机器人(默认 true) */
36
- respondToAt?: boolean;
37
-
38
- /** 是否响应私聊(默认 true) */
39
- respondToPrivate?: boolean;
40
-
41
- /** 触发关键词(可选) */
42
- keywords?: string[];
43
-
44
- /** 忽略的前缀(命令前缀,避免与命令冲突) */
45
- ignorePrefixes?: string[];
46
-
47
- /** 超时时间(毫秒,默认 60000) */
48
- timeout?: number;
49
-
50
- /** 思考中提示(可选) */
51
- thinkingMessage?: string;
52
-
53
- /** 错误消息模板 */
54
- errorTemplate?: string;
55
-
56
- /** Zhin 拥有者 ID 列表 */
57
- owners?: string[];
58
-
59
- /** 机器人管理员 ID 列表 */
60
- botAdmins?: string[];
61
- }
62
-
63
- /**
64
- * AI 触发检查结果
65
- */
66
- export interface AITriggerResult {
67
- triggered: boolean;
68
- content: string;
69
- }
70
-
71
- /**
72
- * 发送者权限信息
73
- */
74
- export interface SenderPermissions {
75
- scope: ToolScope;
76
- isGroupAdmin: boolean;
77
- isGroupOwner: boolean;
78
- isBotAdmin: boolean;
79
- isOwner: boolean;
80
- permissionLevel: ToolPermissionLevel;
81
- }
82
-
83
- // ============================================================================
84
- // 默认配置
85
- // ============================================================================
86
-
87
- export const DEFAULT_AI_TRIGGER_CONFIG: Required<AITriggerConfig> = {
88
- enabled: true,
89
- prefixes: ['#', 'AI:', 'ai:'],
90
- respondToAt: true,
91
- respondToPrivate: true,
92
- keywords: [],
93
- ignorePrefixes: ['/', '!', '!'],
94
- timeout: 60000,
95
- thinkingMessage: '',
96
- errorTemplate: '❌ AI 处理失败: {error}',
97
- owners: [],
98
- botAdmins: [],
99
- };
100
-
101
- // ============================================================================
102
- // 工具函数
103
- // ============================================================================
104
-
105
- /**
106
- * 检查消息是否 @ 了机器人
107
- */
108
- export function isAtBot<T extends object>(message: Message<T>): boolean {
109
- const botId = String(message.$bot);
110
- return message.$content.some(seg => {
111
- return String(seg.data?.qq) === botId || String(seg.data?.user_id) === botId;
112
- });
113
- }
114
-
115
- /**
116
- * 提取消息文本内容(保留富媒体信息)
117
- * 使用 segment.toString 将 MessageElement 转为 XML 格式
118
- */
119
- export function extractTextContent<T extends object>(message: Message<T>): string {
120
- return segment.toString(message.$content);
121
- }
122
-
123
- /**
124
- * 解析 AI 回复中的富媒体内容
125
- * 将字符串中的 XML-like 标签解析为 MessageElement
126
- */
127
- export function parseRichMediaContent(content: string): MessageElement[] {
128
- try {
129
- const parsed = segment.from(content);
130
- const elements = Array.isArray(parsed) ? parsed : [parsed];
131
- return elements.map(el => {
132
- if (typeof el === 'string') {
133
- return { type: 'text', data: { text: el } };
134
- }
135
- return el as MessageElement;
136
- });
137
- } catch (error) {
138
- return [{ type: 'text', data: { text: content } }];
139
- }
140
- }
141
-
142
- /**
143
- * 移除 @ 机器人的部分
144
- */
145
- export function removeAtBot<T extends object>(message: Message<T>): MessageElement[] {
146
- const botId = String(message.$bot);
147
- return message.$content.filter(seg => {
148
- const { type, data } = seg;
149
- if (type !== "at") return true; // 非 at 段全部保留
150
- const userId = String(data?.user_id || data?.qq);
151
- return userId !== botId; // 只移除 @机器人 的段,保留 @其他人
152
- });
153
- }
154
-
155
- /**
156
- * 从消息中推断发送者的权限级别
157
- */
158
- export function inferSenderPermissions<T extends object>(
159
- message: Message<T>,
160
- config: AITriggerConfig
161
- ): SenderPermissions {
162
- const scope: ToolScope = message.$channel?.type as ToolScope || 'private';
163
- const senderId = message.$sender.id;
164
- const senderPermissions = message.$sender.permissions || [];
165
-
166
- const owners = config.owners || [];
167
- const isOwner = owners.includes(senderId);
168
-
169
- const botAdmins = config.botAdmins || [];
170
- const isBotAdmin = isOwner || botAdmins.includes(senderId);
171
-
172
- const isGroupOwner = senderPermissions.includes('owner') ||
173
- senderPermissions.includes('group_owner') ||
174
- message.$sender?.role === 'owner';
175
-
176
- const isGroupAdmin = isGroupOwner ||
177
- senderPermissions.includes('admin') ||
178
- senderPermissions.includes('group_admin') ||
179
- message.$sender?.role === 'admin';
180
-
181
- let permissionLevel: ToolPermissionLevel = 'user';
182
- if (isOwner) permissionLevel = 'owner';
183
- else if (isBotAdmin) permissionLevel = 'bot_admin';
184
- else if (isGroupOwner) permissionLevel = 'group_owner';
185
- else if (isGroupAdmin) permissionLevel = 'group_admin';
186
-
187
- return {
188
- scope,
189
- isGroupAdmin,
190
- isGroupOwner,
191
- isBotAdmin,
192
- isOwner,
193
- permissionLevel,
194
- };
195
- }
196
-
197
- /**
198
- * 检查消息是否应该触发 AI
199
- */
200
- export function shouldTriggerAI<T extends object>(
201
- message: Message<T>,
202
- config: AITriggerConfig
203
- ): AITriggerResult {
204
- const fullConfig = { ...DEFAULT_AI_TRIGGER_CONFIG, ...config };
205
-
206
- if (!fullConfig.enabled) {
207
- return { triggered: false, content: '' };
208
- }
209
-
210
- const text = extractTextContent(message);
211
-
212
- // 检查忽略前缀
213
- for (const prefix of fullConfig.ignorePrefixes) {
214
- if (text.startsWith(prefix)) {
215
- return { triggered: false, content: '' };
216
- }
217
- }
218
-
219
- // 1. 检查前缀触发
220
- for (const prefix of fullConfig.prefixes) {
221
- if (text.startsWith(prefix)) {
222
- return { triggered: true, content: text.slice(prefix.length).trim() };
223
- }
224
- }
225
-
226
- // 2. 检查 @ 触发
227
- if (fullConfig.respondToAt && isAtBot(message)) {
228
- const content = removeAtBot(message);
229
- if (content.length) {
230
- return { triggered: true, content: segment.toString(content) };
231
- }
232
- }
233
-
234
- // 3. 检查私聊触发
235
- if (fullConfig.respondToPrivate && message.$channel?.type === 'private') {
236
- if (text.trim()) {
237
- return { triggered: true, content: text.trim() };
238
- }
239
- }
240
-
241
- // 4. 检查关键词触发
242
- if (fullConfig.keywords.length > 0) {
243
- const lowerText = text.toLowerCase();
244
- for (const keyword of fullConfig.keywords) {
245
- if (lowerText.includes(keyword.toLowerCase())) {
246
- return { triggered: true, content: text };
247
- }
248
- }
249
- }
250
-
251
- return { triggered: false, content: '' };
252
- }
253
-
254
- /**
255
- * 合并配置
256
- */
257
- export function mergeAITriggerConfig(config: AITriggerConfig): Required<AITriggerConfig> {
258
- return { ...DEFAULT_AI_TRIGGER_CONFIG, ...config };
259
- }
@@ -1,108 +0,0 @@
1
- /**
2
- * CommandFeature
3
- * 管理所有插件注册的命令,继承自 Feature 抽象类
4
- */
5
- import { Feature, FeatureJSON } from "../feature.js";
6
- import { MessageCommand } from "../command.js";
7
- import { Message } from "../message.js";
8
- import { Plugin, getPlugin } from "../plugin.js";
9
- import type { RegisteredAdapter, AdapterMessage } from "../types.js";
10
-
11
- /**
12
- * CommandContext 扩展方法类型
13
- */
14
- export interface CommandContextExtensions {
15
- /** 添加命令 */
16
- addCommand<T extends RegisteredAdapter>(command: MessageCommand<T>): () => void;
17
- }
18
-
19
- // 扩展 Plugin 接口
20
- declare module "../plugin.js" {
21
- namespace Plugin {
22
- interface Extensions extends CommandContextExtensions {}
23
- interface Contexts {
24
- command: CommandFeature;
25
- }
26
- }
27
- }
28
-
29
- /**
30
- * 命令服务 Feature
31
- */
32
- export class CommandFeature extends Feature<MessageCommand<RegisteredAdapter>> {
33
- readonly name = 'command' as const;
34
- readonly icon = 'Terminal';
35
- readonly desc = '命令';
36
-
37
- /** 按 pattern 索引 */
38
- readonly byName = new Map<string, MessageCommand<RegisteredAdapter>>();
39
-
40
- /**
41
- * 添加命令
42
- */
43
- add(command: MessageCommand<RegisteredAdapter>, pluginName: string): () => void {
44
- this.byName.set(command.pattern, command);
45
- return super.add(command, pluginName);
46
- }
47
-
48
- /**
49
- * 移除命令
50
- */
51
- remove(command: MessageCommand<RegisteredAdapter>): boolean {
52
- this.byName.delete(command.pattern);
53
- return super.remove(command);
54
- }
55
-
56
- /**
57
- * 按 pattern 获取命令
58
- */
59
- get(pattern: string): MessageCommand<RegisteredAdapter> | undefined {
60
- return this.byName.get(pattern);
61
- }
62
-
63
- /**
64
- * 处理消息,依次尝试匹配命令
65
- */
66
- async handle(message: Message<AdapterMessage<RegisteredAdapter>>, plugin: Plugin): Promise<any> {
67
- for (const command of this.items) {
68
- const result = await command.handle(message, plugin);
69
- if (result) return result;
70
- }
71
- return null;
72
- }
73
-
74
- /**
75
- * 序列化为 JSON
76
- */
77
- toJSON(pluginName?: string): FeatureJSON {
78
- const list = pluginName ? this.getByPlugin(pluginName) : this.items;
79
- return {
80
- name: this.name,
81
- icon: this.icon,
82
- desc: this.desc,
83
- count: list.length,
84
- items: list.map(c => ({
85
- name: c.pattern,
86
- desc: c.helpInfo?.desc,
87
- usage: c.helpInfo?.usage,
88
- examples: c.helpInfo?.examples,
89
- })),
90
- };
91
- }
92
-
93
- /**
94
- * 提供给 Plugin.prototype 的扩展方法
95
- */
96
- get extensions() {
97
- const feature = this;
98
- return {
99
- addCommand<T extends RegisteredAdapter>(command: MessageCommand<T>) {
100
- const plugin = getPlugin();
101
- const dispose = feature.add(command as MessageCommand<RegisteredAdapter>, plugin.name);
102
- plugin.recordFeatureContribution(feature.name, command.pattern);
103
- plugin.onDispose(dispose);
104
- return dispose;
105
- },
106
- };
107
- }
108
- }
@@ -1,242 +0,0 @@
1
- /**
2
- * Group Management — 方法规范与 Tool 工厂
3
- *
4
- * 设计理念:
5
- * 各 IM 平台在适配器内自行实现群管方法(kickMember、muteMember 等),
6
- * 并自行注册 Tool;平台说明使用包内 `skills/<adapter>/SKILL.md`。
7
- *
8
- * 使用方式(在各适配器 start 或注册方法中):
9
- *
10
- * import { createGroupManagementTools, GROUP_MANAGEMENT_SKILL_KEYWORDS, GROUP_MANAGEMENT_SKILL_TAGS } from 'zhin.js';
11
- * const tools = createGroupManagementTools(this, this.name);
12
- * tools.forEach(t => this.addTool(t));
13
- * // 另:包内 skills/<name>/SKILL.md 供 Agent 发现
14
- */
15
-
16
- import type { Tool, ToolPermissionLevel, ToolScope } from '../types.js';
17
-
18
- // ============================================================================
19
- // Adapter 群管理方法规范
20
- // ============================================================================
21
-
22
- /**
23
- * 群管理能力接口。
24
- * Adapter 基类通过此接口声明方法签名,子类选择性覆写。
25
- */
26
- export interface IGroupManagement {
27
- kickMember?(botId: string, sceneId: string, userId: string): Promise<any>;
28
- muteMember?(botId: string, sceneId: string, userId: string, duration?: number): Promise<any>;
29
- setMemberNickname?(botId: string, sceneId: string, userId: string, nickname: string): Promise<any>;
30
- setAdmin?(botId: string, sceneId: string, userId: string, enable?: boolean): Promise<any>;
31
- listMembers?(botId: string, sceneId: string): Promise<any>;
32
- banMember?(botId: string, sceneId: string, userId: string, reason?: string): Promise<any>;
33
- unbanMember?(botId: string, sceneId: string, userId: string): Promise<any>;
34
- setGroupName?(botId: string, sceneId: string, name: string): Promise<any>;
35
- muteAll?(botId: string, sceneId: string, enable?: boolean): Promise<any>;
36
- getGroupInfo?(botId: string, sceneId: string): Promise<any>;
37
- }
38
-
39
- // ============================================================================
40
- // 方法 → Tool 元数据映射
41
- // ============================================================================
42
-
43
- export interface GroupMethodSpec {
44
- method: keyof IGroupManagement;
45
- toolSuffix: string;
46
- description: string;
47
- keywords: string[];
48
- permissionLevel: ToolPermissionLevel;
49
- extraParams: Record<string, { type: string; description: string; default?: any }>;
50
- extraRequired?: string[];
51
- preExecutable?: boolean;
52
- }
53
-
54
- export const GROUP_METHOD_SPECS: GroupMethodSpec[] = [
55
- {
56
- method: 'kickMember',
57
- toolSuffix: 'kick_member',
58
- description: '将成员踢出群/服务器。适用于严重违规、广告号等需要移除的场景。踢出后该成员将无法再进入群聊(部分平台可重新邀请)。如果只需要用户名而没有 user_id,请先调用 list_members 查询',
59
- keywords: ['踢', 'kick', '移除', '踢出'],
60
- permissionLevel: 'group_admin',
61
- extraParams: {
62
- user_id: { type: 'string', description: '目标用户 ID(如果只有昵称,先用 list_members 查询获取)' },
63
- },
64
- extraRequired: ['user_id'],
65
- },
66
- {
67
- method: 'muteMember',
68
- toolSuffix: 'mute_member',
69
- description: '禁言或解除禁言群成员。适用于违规发言、刷屏、骚扰他人等需要临时限制发言的场景。duration 单位为秒,传 0 表示解除禁言。默认禁言 10 分钟(600秒)。如果只有昵称而没有 user_id,请先调用 list_members 查询',
70
- keywords: ['禁言', 'mute', '静音', '解除禁言', '解禁', '闭嘴'],
71
- permissionLevel: 'group_admin',
72
- extraParams: {
73
- user_id: { type: 'string', description: '目标用户 ID(如果只有昵称,先用 list_members 查询获取)' },
74
- duration: { type: 'number', description: '禁言时长(秒),0=解除禁言,默认600(10分钟)。常用值:60=1分钟, 600=10分钟, 3600=1小时, 86400=1天', default: 600 },
75
- },
76
- extraRequired: ['user_id'],
77
- },
78
- {
79
- method: 'setMemberNickname',
80
- toolSuffix: 'set_nickname',
81
- description: '设置群成员的群昵称/名片。仅修改群内显示名称,不影响用户的全局昵称。如果只有昵称而没有 user_id,请先调用 list_members 查询',
82
- keywords: ['昵称', '名片', 'nickname', 'card', '改名片'],
83
- permissionLevel: 'group_admin',
84
- extraParams: {
85
- user_id: { type: 'string', description: '目标用户 ID(如果只有昵称,先用 list_members 查询获取)' },
86
- nickname: { type: 'string', description: '新的群昵称/名片' },
87
- },
88
- extraRequired: ['user_id', 'nickname'],
89
- },
90
- {
91
- method: 'setAdmin',
92
- toolSuffix: 'set_admin',
93
- description: '设置或取消群管理员。注意:此操作需要群主权限,普通管理员无法执行。enable=true 为设置管理员,enable=false 为取消管理员。如果只有昵称而没有 user_id,请先调用 list_members 查询',
94
- keywords: ['管理员', 'admin', '设置管理', '取消管理', '提升管理', '撤销管理'],
95
- permissionLevel: 'group_owner',
96
- extraParams: {
97
- user_id: { type: 'string', description: '目标用户 ID(如果只有昵称,先用 list_members 查询获取)' },
98
- enable: { type: 'boolean', description: 'true=设置为管理员,false=取消管理员身份', default: true },
99
- },
100
- extraRequired: ['user_id'],
101
- },
102
- {
103
- method: 'listMembers',
104
- toolSuffix: 'list_members',
105
- description: '获取群/服务器成员列表。返回所有成员的 ID、昵称、名片、角色等信息。当用户提供昵称/名片而非 ID 时,应先调用此工具查询成员列表,从中匹配到目标用户的 user_id,再执行禁言、踢人等操作',
106
- keywords: ['成员', '列表', 'members', 'list', '查找', '搜索用户'],
107
- permissionLevel: 'user',
108
- extraParams: {},
109
- preExecutable: true,
110
- },
111
- {
112
- method: 'banMember',
113
- toolSuffix: 'ban_member',
114
- description: '永久封禁成员(拉入黑名单)。与踢人(kick)不同,封禁后该成员无法再加入群聊。适用于恶意用户、严重违规等需要永久禁止的场景。如果只有昵称而没有 user_id,请先调用 list_members 查询',
115
- keywords: ['封禁', 'ban', '拉黑', '黑名单'],
116
- permissionLevel: 'group_admin',
117
- extraParams: {
118
- user_id: { type: 'string', description: '目标用户 ID(如果只有昵称,先用 list_members 查询获取)' },
119
- reason: { type: 'string', description: '封禁原因(将记录在封禁日志中)' },
120
- },
121
- extraRequired: ['user_id'],
122
- },
123
- {
124
- method: 'unbanMember',
125
- toolSuffix: 'unban_member',
126
- description: '解除封禁,将成员从黑名单中移除。解除后该成员可以重新加入群聊。如果只有昵称而没有 user_id,请先调用 list_members 查询',
127
- keywords: ['解封', 'unban', '解除封禁', '移出黑名单'],
128
- permissionLevel: 'group_admin',
129
- extraParams: {
130
- user_id: { type: 'string', description: '目标用户 ID(如果只有昵称,先用 list_members 查询获取)' },
131
- },
132
- extraRequired: ['user_id'],
133
- },
134
- {
135
- method: 'setGroupName',
136
- toolSuffix: 'set_group_name',
137
- description: '修改群/服务器名称。修改后所有成员立即可见新群名',
138
- keywords: ['群名', '改名', 'group name', '修改群名'],
139
- permissionLevel: 'group_admin',
140
- extraParams: {
141
- name: { type: 'string', description: '新群名称' },
142
- },
143
- extraRequired: ['name'],
144
- },
145
- {
146
- method: 'muteAll',
147
- toolSuffix: 'mute_all',
148
- description: '开启或关闭全员禁言。开启后除管理员外所有成员都无法发言。适用于紧急维护、重要通知、聊天秩序混乱等场景。enable=true 开启,enable=false 解除',
149
- keywords: ['全员禁言', 'mute all', '全体禁言', '全体解禁'],
150
- permissionLevel: 'group_admin',
151
- extraParams: {
152
- enable: { type: 'boolean', description: 'true=开启全员禁言,false=解除全员禁言', default: true },
153
- },
154
- },
155
- {
156
- method: 'getGroupInfo',
157
- toolSuffix: 'get_group_info',
158
- description: '获取群/服务器基本信息,包括群名、群主、成员数量、创建时间等。用于了解群聊概况',
159
- keywords: ['群信息', 'group info', '群资料', '群详情'],
160
- permissionLevel: 'user',
161
- extraParams: {},
162
- preExecutable: true,
163
- },
164
- ];
165
-
166
- // ============================================================================
167
- // Skill 常量(群管相关 SKILL.md 与文档可复用 keywords/tags)
168
- // ============================================================================
169
-
170
- export const GROUP_MANAGEMENT_SKILL_TAGS = ['group', 'management', 'im', 'admin'];
171
- export const GROUP_MANAGEMENT_SKILL_KEYWORDS = [
172
- '群管理', '踢人', '禁言', '封禁', '管理员', '群名',
173
- '成员', 'kick', 'mute', 'ban', 'admin', 'members',
174
- ];
175
-
176
- // ============================================================================
177
- // 工厂:根据已实现的方法为指定适配器生成群管 Tool 列表(各平台自行调用并 addTool)
178
- // ============================================================================
179
-
180
- export function createGroupManagementTools(
181
- adapter: IGroupManagement,
182
- prefix: string,
183
- ): Tool[] {
184
- const tools: Tool[] = [];
185
- for (const spec of GROUP_METHOD_SPECS) {
186
- const fn = adapter[spec.method];
187
- if (typeof fn !== 'function') continue;
188
-
189
- const properties: Record<string, any> = {
190
- bot_id: { type: 'string', description: 'Bot ID', contextKey: 'botId' },
191
- scene_id: { type: 'string', description: '群/服务器 ID', contextKey: 'sceneId' },
192
- };
193
- const required: string[] = ['bot_id', 'scene_id'];
194
- for (const [name, schema] of Object.entries(spec.extraParams)) {
195
- properties[name] = schema;
196
- }
197
- if (spec.extraRequired) required.push(...spec.extraRequired);
198
-
199
- const boundFn = fn.bind(adapter);
200
- tools.push({
201
- name: `${prefix}_${spec.toolSuffix}`,
202
- description: `${spec.description} (${prefix})`,
203
- parameters: { type: 'object' as const, properties, required },
204
- execute: async (args: Record<string, any>) => {
205
- const { bot_id, scene_id, ...rest } = args;
206
- const methodArgs = buildMethodArgs(spec.method, bot_id, scene_id, rest);
207
- return (boundFn as (...a: any[]) => Promise<any>).apply(adapter, methodArgs);
208
- },
209
- tags: ['group', 'management', prefix],
210
- keywords: spec.keywords,
211
- permissionLevel: spec.permissionLevel,
212
- scopes: ['group', 'channel'] as ToolScope[],
213
- preExecutable: spec.preExecutable,
214
- });
215
- }
216
- return tools;
217
- }
218
-
219
- // ============================================================================
220
- // 参数映射(method → 有序参数列表)
221
- // ============================================================================
222
-
223
- export function buildMethodArgs(
224
- method: keyof IGroupManagement,
225
- botId: string,
226
- sceneId: string,
227
- rest: Record<string, any>,
228
- ): any[] {
229
- switch (method) {
230
- case 'kickMember': return [botId, sceneId, rest.user_id];
231
- case 'muteMember': return [botId, sceneId, rest.user_id, rest.duration ?? 600];
232
- case 'setMemberNickname': return [botId, sceneId, rest.user_id, rest.nickname];
233
- case 'setAdmin': return [botId, sceneId, rest.user_id, rest.enable ?? true];
234
- case 'listMembers': return [botId, sceneId];
235
- case 'banMember': return [botId, sceneId, rest.user_id, rest.reason];
236
- case 'unbanMember': return [botId, sceneId, rest.user_id];
237
- case 'setGroupName': return [botId, sceneId, rest.name];
238
- case 'muteAll': return [botId, sceneId, rest.enable ?? true];
239
- case 'getGroupInfo': return [botId, sceneId];
240
- default: return [botId, sceneId, ...(Object.values(rest) as any[])];
241
- }
242
- }