@zhin.js/core 1.0.24 → 1.0.26

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 (211) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +84 -342
  3. package/lib/adapter.d.ts +45 -1
  4. package/lib/adapter.d.ts.map +1 -1
  5. package/lib/adapter.js +182 -1
  6. package/lib/adapter.js.map +1 -1
  7. package/lib/ai/agent.d.ts +126 -0
  8. package/lib/ai/agent.d.ts.map +1 -0
  9. package/lib/ai/agent.js +645 -0
  10. package/lib/ai/agent.js.map +1 -0
  11. package/lib/ai/context-manager.d.ts +213 -0
  12. package/lib/ai/context-manager.d.ts.map +1 -0
  13. package/lib/ai/context-manager.js +313 -0
  14. package/lib/ai/context-manager.js.map +1 -0
  15. package/lib/ai/conversation-memory.d.ts +181 -0
  16. package/lib/ai/conversation-memory.d.ts.map +1 -0
  17. package/lib/ai/conversation-memory.js +581 -0
  18. package/lib/ai/conversation-memory.js.map +1 -0
  19. package/lib/ai/follow-up.d.ts +131 -0
  20. package/lib/ai/follow-up.d.ts.map +1 -0
  21. package/lib/ai/follow-up.js +265 -0
  22. package/lib/ai/follow-up.js.map +1 -0
  23. package/lib/ai/index.d.ts +29 -0
  24. package/lib/ai/index.d.ts.map +1 -0
  25. package/lib/ai/index.js +34 -0
  26. package/lib/ai/index.js.map +1 -0
  27. package/lib/ai/init.d.ts +30 -0
  28. package/lib/ai/init.d.ts.map +1 -0
  29. package/lib/ai/init.js +424 -0
  30. package/lib/ai/init.js.map +1 -0
  31. package/lib/ai/output.d.ts +93 -0
  32. package/lib/ai/output.d.ts.map +1 -0
  33. package/lib/ai/output.js +176 -0
  34. package/lib/ai/output.js.map +1 -0
  35. package/lib/ai/providers/anthropic.d.ts +23 -0
  36. package/lib/ai/providers/anthropic.d.ts.map +1 -0
  37. package/lib/ai/providers/anthropic.js +322 -0
  38. package/lib/ai/providers/anthropic.js.map +1 -0
  39. package/lib/ai/providers/base.d.ts +43 -0
  40. package/lib/ai/providers/base.d.ts.map +1 -0
  41. package/lib/ai/providers/base.js +135 -0
  42. package/lib/ai/providers/base.js.map +1 -0
  43. package/lib/ai/providers/index.d.ts +12 -0
  44. package/lib/ai/providers/index.d.ts.map +1 -0
  45. package/lib/ai/providers/index.js +9 -0
  46. package/lib/ai/providers/index.js.map +1 -0
  47. package/lib/ai/providers/ollama.d.ts +25 -0
  48. package/lib/ai/providers/ollama.d.ts.map +1 -0
  49. package/lib/ai/providers/ollama.js +243 -0
  50. package/lib/ai/providers/ollama.js.map +1 -0
  51. package/lib/ai/providers/openai.d.ts +46 -0
  52. package/lib/ai/providers/openai.d.ts.map +1 -0
  53. package/lib/ai/providers/openai.js +132 -0
  54. package/lib/ai/providers/openai.js.map +1 -0
  55. package/lib/ai/rate-limiter.d.ts +38 -0
  56. package/lib/ai/rate-limiter.d.ts.map +1 -0
  57. package/lib/ai/rate-limiter.js +86 -0
  58. package/lib/ai/rate-limiter.js.map +1 -0
  59. package/lib/ai/service.d.ts +81 -0
  60. package/lib/ai/service.d.ts.map +1 -0
  61. package/lib/ai/service.js +274 -0
  62. package/lib/ai/service.js.map +1 -0
  63. package/lib/ai/session.d.ts +186 -0
  64. package/lib/ai/session.d.ts.map +1 -0
  65. package/lib/ai/session.js +443 -0
  66. package/lib/ai/session.js.map +1 -0
  67. package/lib/ai/tone-detector.d.ts +19 -0
  68. package/lib/ai/tone-detector.d.ts.map +1 -0
  69. package/lib/ai/tone-detector.js +72 -0
  70. package/lib/ai/tone-detector.js.map +1 -0
  71. package/lib/ai/tools.d.ts +45 -0
  72. package/lib/ai/tools.d.ts.map +1 -0
  73. package/lib/ai/tools.js +206 -0
  74. package/lib/ai/tools.js.map +1 -0
  75. package/lib/ai/types.d.ts +264 -0
  76. package/lib/ai/types.d.ts.map +1 -0
  77. package/lib/ai/types.js +6 -0
  78. package/lib/ai/types.js.map +1 -0
  79. package/lib/ai/user-profile.d.ts +56 -0
  80. package/lib/ai/user-profile.d.ts.map +1 -0
  81. package/lib/ai/user-profile.js +130 -0
  82. package/lib/ai/user-profile.js.map +1 -0
  83. package/lib/ai/zhin-agent.d.ts +165 -0
  84. package/lib/ai/zhin-agent.d.ts.map +1 -0
  85. package/lib/ai/zhin-agent.js +707 -0
  86. package/lib/ai/zhin-agent.js.map +1 -0
  87. package/lib/built/adapter-process.d.ts +4 -0
  88. package/lib/built/adapter-process.d.ts.map +1 -1
  89. package/lib/built/adapter-process.js +94 -0
  90. package/lib/built/adapter-process.js.map +1 -1
  91. package/lib/built/ai-trigger.d.ts +89 -0
  92. package/lib/built/ai-trigger.d.ts.map +1 -0
  93. package/lib/built/ai-trigger.js +166 -0
  94. package/lib/built/ai-trigger.js.map +1 -0
  95. package/lib/built/command.d.ts +33 -17
  96. package/lib/built/command.d.ts.map +1 -1
  97. package/lib/built/command.js +71 -44
  98. package/lib/built/command.js.map +1 -1
  99. package/lib/built/component.d.ts +42 -15
  100. package/lib/built/component.d.ts.map +1 -1
  101. package/lib/built/component.js +84 -52
  102. package/lib/built/component.js.map +1 -1
  103. package/lib/built/config.d.ts +54 -5
  104. package/lib/built/config.d.ts.map +1 -1
  105. package/lib/built/config.js +76 -10
  106. package/lib/built/config.js.map +1 -1
  107. package/lib/built/cron.d.ts +41 -18
  108. package/lib/built/cron.d.ts.map +1 -1
  109. package/lib/built/cron.js +106 -63
  110. package/lib/built/cron.js.map +1 -1
  111. package/lib/built/database.d.ts +55 -6
  112. package/lib/built/database.d.ts.map +1 -1
  113. package/lib/built/database.js +93 -22
  114. package/lib/built/database.js.map +1 -1
  115. package/lib/built/dispatcher.d.ts +118 -0
  116. package/lib/built/dispatcher.d.ts.map +1 -0
  117. package/lib/built/dispatcher.js +196 -0
  118. package/lib/built/dispatcher.js.map +1 -0
  119. package/lib/built/permission.d.ts +45 -5
  120. package/lib/built/permission.d.ts.map +1 -1
  121. package/lib/built/permission.js +56 -11
  122. package/lib/built/permission.js.map +1 -1
  123. package/lib/built/skill.d.ts +117 -0
  124. package/lib/built/skill.d.ts.map +1 -0
  125. package/lib/built/skill.js +191 -0
  126. package/lib/built/skill.js.map +1 -0
  127. package/lib/built/tool.d.ts +188 -0
  128. package/lib/built/tool.d.ts.map +1 -0
  129. package/lib/built/tool.js +749 -0
  130. package/lib/built/tool.js.map +1 -0
  131. package/lib/feature.d.ts +75 -0
  132. package/lib/feature.d.ts.map +1 -0
  133. package/lib/feature.js +69 -0
  134. package/lib/feature.js.map +1 -0
  135. package/lib/index.d.ts +6 -0
  136. package/lib/index.d.ts.map +1 -1
  137. package/lib/index.js +11 -0
  138. package/lib/index.js.map +1 -1
  139. package/lib/plugin.d.ts +53 -18
  140. package/lib/plugin.d.ts.map +1 -1
  141. package/lib/plugin.js +301 -31
  142. package/lib/plugin.js.map +1 -1
  143. package/lib/types.d.ts +248 -9
  144. package/lib/types.d.ts.map +1 -1
  145. package/lib/utils.d.ts.map +1 -1
  146. package/lib/utils.js +38 -12
  147. package/lib/utils.js.map +1 -1
  148. package/package.json +4 -4
  149. package/src/adapter.ts +206 -2
  150. package/src/ai/agent.ts +772 -0
  151. package/src/ai/context-manager.ts +440 -0
  152. package/src/ai/conversation-memory.ts +774 -0
  153. package/src/ai/follow-up.ts +357 -0
  154. package/src/ai/index.ts +128 -0
  155. package/src/ai/init.ts +502 -0
  156. package/src/ai/output.ts +261 -0
  157. package/src/ai/providers/anthropic.ts +375 -0
  158. package/src/ai/providers/base.ts +173 -0
  159. package/src/ai/providers/index.ts +13 -0
  160. package/src/ai/providers/ollama.ts +292 -0
  161. package/src/ai/providers/openai.ts +167 -0
  162. package/src/ai/rate-limiter.ts +129 -0
  163. package/src/ai/service.ts +319 -0
  164. package/src/ai/session.ts +544 -0
  165. package/src/ai/tone-detector.ts +89 -0
  166. package/src/ai/tools.ts +218 -0
  167. package/src/ai/types.ts +296 -0
  168. package/src/ai/user-profile.ts +181 -0
  169. package/src/ai/zhin-agent.ts +845 -0
  170. package/src/built/adapter-process.ts +99 -0
  171. package/src/built/ai-trigger.ts +259 -0
  172. package/src/built/command.ts +75 -69
  173. package/src/built/component.ts +94 -76
  174. package/src/built/config.ts +238 -128
  175. package/src/built/cron.ts +117 -101
  176. package/src/built/database.ts +128 -33
  177. package/src/built/dispatcher.ts +332 -0
  178. package/src/built/permission.ts +146 -54
  179. package/src/built/skill.ts +280 -0
  180. package/src/built/tool.ts +928 -0
  181. package/src/feature.ts +113 -0
  182. package/src/index.ts +11 -0
  183. package/src/plugin.ts +359 -69
  184. package/src/types.ts +306 -11
  185. package/src/utils.ts +37 -13
  186. package/tests/adapter.test.ts +153 -1
  187. package/tests/ai/agent.test.ts +614 -0
  188. package/tests/ai/ai-trigger.test.ts +368 -0
  189. package/tests/ai/context-manager.test.ts +413 -0
  190. package/tests/ai/conversation-memory.test.ts +128 -0
  191. package/tests/ai/follow-up.test.ts +175 -0
  192. package/tests/ai/integration.test.ts +584 -0
  193. package/tests/ai/output.test.ts +128 -0
  194. package/tests/ai/providers.integration.test.ts +227 -0
  195. package/tests/ai/rate-limiter.test.ts +108 -0
  196. package/tests/ai/session.test.ts +375 -0
  197. package/tests/ai/setup.ts +308 -0
  198. package/tests/ai/tone-detector.test.ts +80 -0
  199. package/tests/ai/tool.test.ts +800 -0
  200. package/tests/ai/tools-builtin.test.ts +346 -0
  201. package/tests/ai/user-profile.test.ts +73 -0
  202. package/tests/ai/zhin-agent.test.ts +177 -0
  203. package/tests/component-new.test.ts +17 -6
  204. package/tests/config.test.ts +46 -0
  205. package/tests/cron.test.ts +94 -5
  206. package/tests/dispatcher.test.ts +146 -0
  207. package/tests/feature.test.ts +145 -0
  208. package/tests/features-builtin.test.ts +191 -0
  209. package/tests/plugin.test.ts +88 -14
  210. package/tests/skill-feature.test.ts +179 -0
  211. package/tests/tool-feature.test.ts +254 -0
package/src/adapter.ts CHANGED
@@ -2,15 +2,23 @@ import { Bot } from "./bot.js";
2
2
  import { Plugin } from "./plugin.js";
3
3
  import { EventEmitter } from "events";
4
4
  import { Message } from "./message.js";
5
- import { BeforeSendHandler, SendOptions } from "./types.js";
5
+ import { BeforeSendHandler, SendOptions, Tool, ToolContext } from "./types.js";
6
6
  import { segment } from "./utils.js";
7
+ import { ZhinTool, isZhinTool, type ToolInput } from "./built/tool.js";
8
+ import type { Skill, SkillFeature } from "./built/skill.js";
7
9
  /**
8
10
  * Adapter类:适配器抽象,管理多平台Bot实例。
9
11
  * 负责根据配置启动/关闭各平台机器人,统一异常处理。
12
+ *
13
+ * 适配器可以提供 AI 工具,供 AI 服务调用。
10
14
  */
11
15
  export abstract class Adapter<R extends Bot = Bot> extends EventEmitter<Adapter.Lifecycle> {
12
16
  /** 当前适配器下所有Bot实例,key为bot名称 */
13
17
  public bots: Map<string, R> = new Map<string, R>();
18
+ /** 适配器提供的工具 */
19
+ public tools: Map<string, Tool> = new Map<string, Tool>();
20
+ /** Skill 注销函数(declareSkill 时设置) */
21
+ private _skillDispose?: () => void;
14
22
  /**
15
23
  * 构造函数
16
24
  * @param name 适配器名称(如 'process'、'qq' 等)
@@ -30,7 +38,19 @@ export abstract class Adapter<R extends Bot = Bot> extends EventEmitter<Adapter.
30
38
  })
31
39
  this.on('message.receive', (message) => {
32
40
  this.logger.info(`${message.$bot} recv ${message.$channel.type}(${message.$channel.id}):${segment.raw(message.$content)}`);
33
- this.plugin?.middleware(message, async ()=>{});
41
+ const rootPlugin = this.plugin?.root || this.plugin;
42
+ // 优先使用 MessageDispatcher(新架构),回退到旧中间件链(兼容)
43
+ const dispatcher = rootPlugin?.inject('dispatcher' as any) as any;
44
+ if (dispatcher && typeof dispatcher.dispatch === 'function') {
45
+ void dispatcher.dispatch(message).catch((err: unknown) => {
46
+ this.logger.error('dispatcher.dispatch(message) failed', err);
47
+ });
48
+ } else {
49
+ // 旧中间件链回退
50
+ void Promise.resolve(rootPlugin?.middleware(message, async () => {})).catch((err: unknown) => {
51
+ this.logger.error('rootPlugin.middleware(message, next) failed', err);
52
+ });
53
+ }
34
54
  });
35
55
  }
36
56
  abstract createBot(config: Adapter.BotConfig<R>): R;
@@ -85,6 +105,10 @@ export abstract class Adapter<R extends Bot = Bot> extends EventEmitter<Adapter.
85
105
  }
86
106
  // 清理 bots Map
87
107
  this.bots.clear();
108
+
109
+ // 清理 Skill
110
+ this._skillDispose?.();
111
+ this._skillDispose = undefined;
88
112
 
89
113
  // 从 adapters 数组中移除
90
114
  const idx = this.plugin.root.adapters.indexOf(this.name);
@@ -101,6 +125,186 @@ export abstract class Adapter<R extends Bot = Bot> extends EventEmitter<Adapter.
101
125
  throw error;
102
126
  }
103
127
  }
128
+
129
+ /**
130
+ * 注册工具
131
+ * @param input 工具定义(支持 Tool 对象或 ZhinTool 实例)
132
+ * @returns 返回一个移除工具的函数
133
+ */
134
+ addTool(input: ToolInput): () => void {
135
+ // 如果是 ZhinTool 实例,转换为 Tool 对象
136
+ const tool: Tool = isZhinTool(input) ? input.toTool() : input;
137
+
138
+ // 自动添加适配器源标识
139
+ const toolWithSource: Tool = {
140
+ ...tool,
141
+ source: tool.source || `adapter:${this.name}`,
142
+ tags: [...(tool.tags || []), 'adapter', this.name],
143
+ };
144
+ this.tools.set(tool.name, toolWithSource);
145
+
146
+ // 同步到全局 ToolFeature(如果可用),使适配器工具出现在插件 features 统计中
147
+ let globalDispose: (() => void) | undefined;
148
+ const toolFeature = this.plugin?.root?.inject('tool' as any) as any;
149
+ if (toolFeature && typeof toolFeature.addTool === 'function') {
150
+ const adapterPluginName = this.plugin?.name || `adapter:${this.name}`;
151
+ globalDispose = toolFeature.addTool(toolWithSource, adapterPluginName, false);
152
+ // 记录到宿主插件的 feature 贡献
153
+ this.plugin?.recordFeatureContribution('tool', tool.name);
154
+ }
155
+
156
+ return () => {
157
+ this.tools.delete(tool.name);
158
+ globalDispose?.();
159
+ };
160
+ }
161
+
162
+ /**
163
+ * 获取所有注册的工具
164
+ * @returns 工具数组
165
+ */
166
+ getTools(): Tool[] {
167
+ return Array.from(this.tools.values());
168
+ }
169
+
170
+ /**
171
+ * 根据名称获取工具
172
+ * @param name 工具名称
173
+ * @returns 工具定义或 undefined
174
+ */
175
+ getTool(name: string): Tool | undefined {
176
+ return this.tools.get(name);
177
+ }
178
+
179
+ /**
180
+ * 声明适配器的 Skill(将 this.tools 聚合为一个 Skill 注册到 SkillFeature)
181
+ *
182
+ * @param metadata Skill 元数据
183
+ * - description: 平台级能力描述
184
+ * - keywords: 额外的触发关键词(可选,会自动从工具中聚合)
185
+ * - tags: 额外的分类标签(可选,会自动从工具中聚合)
186
+ * - conventions: 平台调用约定(可选,拼接到 description 末尾)
187
+ */
188
+ declareSkill(metadata: {
189
+ description: string;
190
+ keywords?: string[];
191
+ tags?: string[];
192
+ conventions?: string;
193
+ }): void {
194
+ const skillFeature = this.plugin?.root?.inject('skill' as any) as SkillFeature | undefined;
195
+ if (!skillFeature) {
196
+ this.logger.debug(`declareSkill: SkillFeature 不可用,跳过 Skill 注册`);
197
+ return;
198
+ }
199
+
200
+ // 收集适配器所有工具
201
+ const tools = this.getTools();
202
+
203
+ // 聚合关键词:metadata 声明 + 工具自带
204
+ const allKeywords = new Set<string>(metadata.keywords || []);
205
+ for (const tool of tools) {
206
+ if (tool.keywords) {
207
+ for (const kw of tool.keywords) {
208
+ allKeywords.add(kw);
209
+ }
210
+ }
211
+ }
212
+
213
+ // 聚合标签:metadata 声明 + 工具自带
214
+ const allTags = new Set<string>(metadata.tags || []);
215
+ for (const tool of tools) {
216
+ if (tool.tags) {
217
+ for (const tag of tool.tags) {
218
+ allTags.add(tag);
219
+ }
220
+ }
221
+ }
222
+
223
+ // 拼接描述:基础描述 + 调用约定
224
+ let description = metadata.description;
225
+ if (metadata.conventions) {
226
+ description += `\n\n调用约定:${metadata.conventions}`;
227
+ }
228
+
229
+ const pluginName = this.plugin?.name || `adapter:${this.name}`;
230
+ const skill: Skill = {
231
+ name: `adapter:${this.name}`,
232
+ description,
233
+ tools,
234
+ keywords: Array.from(allKeywords),
235
+ tags: Array.from(allTags),
236
+ pluginName,
237
+ };
238
+
239
+ // 清理旧的 Skill(如果有)
240
+ this._skillDispose?.();
241
+
242
+ // 注册到 SkillFeature
243
+ this._skillDispose = skillFeature.add(skill, pluginName);
244
+ this.plugin?.recordFeatureContribution('skill', `adapter:${this.name}`);
245
+
246
+ this.logger.debug(`declareSkill: 已注册 Skill "${skill.name}",包含 ${tools.length} 个工具`);
247
+ }
248
+
249
+ /**
250
+ * 提供默认的适配器工具(子类可覆盖)
251
+ * 包含发送消息、撤回消息等基础能力
252
+ */
253
+ protected registerDefaultTools(): void {
254
+ // 发送消息工具
255
+ this.addTool({
256
+ name: `${this.name}_send_message`,
257
+ description: `使用 ${this.name} 适配器发送消息到指定目标`,
258
+ parameters: {
259
+ type: 'object',
260
+ properties: {
261
+ bot: {
262
+ type: 'string',
263
+ description: 'Bot 名称/ID',
264
+ },
265
+ id: {
266
+ type: 'string',
267
+ description: '目标 ID(用户/群/频道)',
268
+ },
269
+ type: {
270
+ type: 'string',
271
+ description: '消息类型',
272
+ },
273
+ content: {
274
+ type: 'string',
275
+ description: '消息内容',
276
+ },
277
+ },
278
+ required: ['bot', 'id', 'type', 'content'],
279
+ },
280
+ execute: async (args) => {
281
+ const { bot, id, type, content } = args;
282
+ return await this.sendMessage({
283
+ context: this.name,
284
+ bot,
285
+ id,
286
+ type: type as 'private' | 'group' | 'channel',
287
+ content,
288
+ });
289
+ },
290
+ });
291
+
292
+ // 获取 Bot 列表工具
293
+ this.addTool({
294
+ name: `${this.name}_list_bots`,
295
+ description: `获取 ${this.name} 适配器下所有已连接的 Bot 列表`,
296
+ parameters: {
297
+ type: 'object',
298
+ properties: {},
299
+ },
300
+ execute: async () => {
301
+ return Array.from(this.bots.entries()).map(([id, bot]) => ({
302
+ id,
303
+ connected: bot.$connected,
304
+ }));
305
+ },
306
+ });
307
+ }
104
308
  }
105
309
  export interface Adapters {}
106
310
  export namespace Adapter {