@zhin.js/core 1.0.25 → 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 (200) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +84 -342
  3. package/lib/adapter.d.ts +17 -0
  4. package/lib/adapter.d.ts.map +1 -1
  5. package/lib/adapter.js +84 -2
  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/ai-trigger.d.ts.map +1 -1
  88. package/lib/built/ai-trigger.js +7 -3
  89. package/lib/built/ai-trigger.js.map +1 -1
  90. package/lib/built/command.d.ts +33 -17
  91. package/lib/built/command.d.ts.map +1 -1
  92. package/lib/built/command.js +71 -44
  93. package/lib/built/command.js.map +1 -1
  94. package/lib/built/component.d.ts +42 -15
  95. package/lib/built/component.d.ts.map +1 -1
  96. package/lib/built/component.js +84 -52
  97. package/lib/built/component.js.map +1 -1
  98. package/lib/built/config.d.ts +54 -5
  99. package/lib/built/config.d.ts.map +1 -1
  100. package/lib/built/config.js +76 -10
  101. package/lib/built/config.js.map +1 -1
  102. package/lib/built/cron.d.ts +41 -18
  103. package/lib/built/cron.d.ts.map +1 -1
  104. package/lib/built/cron.js +106 -63
  105. package/lib/built/cron.js.map +1 -1
  106. package/lib/built/database.d.ts +55 -6
  107. package/lib/built/database.d.ts.map +1 -1
  108. package/lib/built/database.js +93 -22
  109. package/lib/built/database.js.map +1 -1
  110. package/lib/built/dispatcher.d.ts +118 -0
  111. package/lib/built/dispatcher.d.ts.map +1 -0
  112. package/lib/built/dispatcher.js +196 -0
  113. package/lib/built/dispatcher.js.map +1 -0
  114. package/lib/built/permission.d.ts +45 -5
  115. package/lib/built/permission.d.ts.map +1 -1
  116. package/lib/built/permission.js +56 -11
  117. package/lib/built/permission.js.map +1 -1
  118. package/lib/built/skill.d.ts +117 -0
  119. package/lib/built/skill.d.ts.map +1 -0
  120. package/lib/built/skill.js +191 -0
  121. package/lib/built/skill.js.map +1 -0
  122. package/lib/built/tool.d.ts +71 -164
  123. package/lib/built/tool.d.ts.map +1 -1
  124. package/lib/built/tool.js +212 -297
  125. package/lib/built/tool.js.map +1 -1
  126. package/lib/feature.d.ts +75 -0
  127. package/lib/feature.d.ts.map +1 -0
  128. package/lib/feature.js +69 -0
  129. package/lib/feature.js.map +1 -0
  130. package/lib/index.d.ts +4 -0
  131. package/lib/index.d.ts.map +1 -1
  132. package/lib/index.js +7 -0
  133. package/lib/index.js.map +1 -1
  134. package/lib/plugin.d.ts +25 -17
  135. package/lib/plugin.d.ts.map +1 -1
  136. package/lib/plugin.js +180 -20
  137. package/lib/plugin.js.map +1 -1
  138. package/lib/types.d.ts +4 -9
  139. package/lib/types.d.ts.map +1 -1
  140. package/package.json +4 -4
  141. package/src/adapter.ts +101 -2
  142. package/src/ai/agent.ts +772 -0
  143. package/src/ai/context-manager.ts +440 -0
  144. package/src/ai/conversation-memory.ts +774 -0
  145. package/src/ai/follow-up.ts +357 -0
  146. package/src/ai/index.ts +128 -0
  147. package/src/ai/init.ts +502 -0
  148. package/src/ai/output.ts +261 -0
  149. package/src/ai/providers/anthropic.ts +375 -0
  150. package/src/ai/providers/base.ts +173 -0
  151. package/src/ai/providers/index.ts +13 -0
  152. package/src/ai/providers/ollama.ts +292 -0
  153. package/src/ai/providers/openai.ts +167 -0
  154. package/src/ai/rate-limiter.ts +129 -0
  155. package/src/ai/service.ts +319 -0
  156. package/src/ai/session.ts +544 -0
  157. package/src/ai/tone-detector.ts +89 -0
  158. package/src/ai/tools.ts +218 -0
  159. package/src/ai/types.ts +296 -0
  160. package/src/ai/user-profile.ts +181 -0
  161. package/src/ai/zhin-agent.ts +845 -0
  162. package/src/built/ai-trigger.ts +6 -3
  163. package/src/built/command.ts +75 -69
  164. package/src/built/component.ts +94 -76
  165. package/src/built/config.ts +238 -128
  166. package/src/built/cron.ts +117 -101
  167. package/src/built/database.ts +128 -33
  168. package/src/built/dispatcher.ts +332 -0
  169. package/src/built/permission.ts +146 -54
  170. package/src/built/skill.ts +280 -0
  171. package/src/built/tool.ts +245 -366
  172. package/src/feature.ts +113 -0
  173. package/src/index.ts +7 -0
  174. package/src/plugin.ts +198 -33
  175. package/src/types.ts +6 -10
  176. package/tests/adapter.test.ts +153 -1
  177. package/tests/ai/agent.test.ts +614 -0
  178. package/tests/ai/ai-trigger.test.ts +368 -0
  179. package/tests/ai/context-manager.test.ts +413 -0
  180. package/tests/ai/conversation-memory.test.ts +128 -0
  181. package/tests/ai/follow-up.test.ts +175 -0
  182. package/tests/ai/integration.test.ts +584 -0
  183. package/tests/ai/output.test.ts +128 -0
  184. package/tests/ai/providers.integration.test.ts +227 -0
  185. package/tests/ai/rate-limiter.test.ts +108 -0
  186. package/tests/ai/session.test.ts +375 -0
  187. package/tests/ai/setup.ts +308 -0
  188. package/tests/ai/tone-detector.test.ts +80 -0
  189. package/tests/ai/tool.test.ts +800 -0
  190. package/tests/ai/tools-builtin.test.ts +346 -0
  191. package/tests/ai/user-profile.test.ts +73 -0
  192. package/tests/ai/zhin-agent.test.ts +177 -0
  193. package/tests/config.test.ts +46 -0
  194. package/tests/cron.test.ts +94 -5
  195. package/tests/dispatcher.test.ts +146 -0
  196. package/tests/feature.test.ts +145 -0
  197. package/tests/features-builtin.test.ts +191 -0
  198. package/tests/plugin.test.ts +88 -14
  199. package/tests/skill-feature.test.ts +179 -0
  200. package/tests/tool-feature.test.ts +254 -0
@@ -0,0 +1,280 @@
1
+ /**
2
+ * SkillFeature — AI 可见能力描述层
3
+ *
4
+ * 核心概念:
5
+ * Plugin = 运行时容器(生命周期、服务注册、中间件)
6
+ * Skill = AI 可见的能力接口(名称、描述、工具列表)
7
+ *
8
+ * 每个 Plugin 可以声明一个 Skill 描述,告诉 AI Agent:
9
+ * "我叫什么、我能做什么、我有哪些工具"
10
+ *
11
+ * SkillFeature 全局收集所有 Skill,供 Agent 进行两级过滤:
12
+ * 1. 粗筛:根据用户消息选择相关 Skill
13
+ * 2. 细筛:从选中 Skill 内选择具体 Tool
14
+ */
15
+
16
+ import { Feature, FeatureJSON } from '../feature.js';
17
+ import { Plugin, getPlugin } from '../plugin.js';
18
+ import type { Tool } from '../types.js';
19
+
20
+ // ============================================================================
21
+ // Skill 接口
22
+ // ============================================================================
23
+
24
+ /**
25
+ * Skill — AI 可见的能力描述
26
+ */
27
+ export interface Skill {
28
+ /** 技能名称(通常与插件名一致) */
29
+ name: string;
30
+
31
+ /** 技能描述(AI 用来理解这个 Skill 的用途) */
32
+ description: string;
33
+
34
+ /** 该 Skill 提供的工具列表 */
35
+ tools: Tool[];
36
+
37
+ /**
38
+ * 触发关键词
39
+ * 当用户消息包含这些关键词时,优先选择此 Skill
40
+ */
41
+ keywords?: string[];
42
+
43
+ /**
44
+ * 分类标签
45
+ * 用于按领域分组(如 'news', 'weather', 'entertainment')
46
+ */
47
+ tags?: string[];
48
+
49
+ /** 来源插件名 */
50
+ pluginName: string;
51
+ }
52
+
53
+ /**
54
+ * Skill 元数据 — 开发者在插件中声明
55
+ * 由 plugin.declareSkill() 注册
56
+ */
57
+ export interface SkillMetadata {
58
+ /** 技能描述(必填) */
59
+ description: string;
60
+
61
+ /** 触发关键词(可选,自动从工具中聚合) */
62
+ keywords?: string[];
63
+
64
+ /** 分类标签(可选) */
65
+ tags?: string[];
66
+ }
67
+
68
+ // ============================================================================
69
+ // 扩展 Plugin 接口
70
+ // ============================================================================
71
+
72
+ export interface SkillContextExtensions {
73
+ /**
74
+ * 声明本插件的 Skill 元数据
75
+ * 调用后,插件的工具会自动聚合为一个 Skill 注册到 SkillFeature
76
+ */
77
+ declareSkill(metadata: SkillMetadata): void;
78
+ }
79
+
80
+ declare module '../plugin.js' {
81
+ namespace Plugin {
82
+ interface Extensions extends SkillContextExtensions {}
83
+ interface Contexts {
84
+ skill: SkillFeature;
85
+ }
86
+ }
87
+ }
88
+
89
+ // ============================================================================
90
+ // SkillFeature 实现
91
+ // ============================================================================
92
+
93
+ export class SkillFeature extends Feature<Skill> {
94
+ readonly name = 'skill' as const;
95
+ readonly icon = 'Brain';
96
+ readonly desc = '技能';
97
+
98
+ /** 按名称索引 */
99
+ readonly byName = new Map<string, Skill>();
100
+
101
+ /**
102
+ * 添加 Skill
103
+ */
104
+ add(skill: Skill, pluginName: string): () => void {
105
+ this.byName.set(skill.name, skill);
106
+ return super.add(skill, pluginName);
107
+ }
108
+
109
+ /**
110
+ * 移除 Skill
111
+ */
112
+ remove(skill: Skill): boolean {
113
+ this.byName.delete(skill.name);
114
+ return super.remove(skill);
115
+ }
116
+
117
+ /**
118
+ * 按名称获取 Skill
119
+ */
120
+ get(name: string): Skill | undefined {
121
+ return this.byName.get(name);
122
+ }
123
+
124
+ /**
125
+ * 获取所有已注册 Skill
126
+ */
127
+ getAll(): Skill[] {
128
+ return [...this.items];
129
+ }
130
+
131
+ /**
132
+ * 按关键词/标签搜索相关 Skill
133
+ * 返回按相关性排序的 Skill 列表
134
+ */
135
+ search(query: string, options?: { maxResults?: number }): Skill[] {
136
+ const maxResults = options?.maxResults ?? 5;
137
+ const scored = this.items
138
+ .map(skill => ({ skill, score: this.#scoreSkill(skill, query) }))
139
+ .filter(({ score }) => score > 0)
140
+ .sort((a, b) => b.score - a.score)
141
+ .slice(0, maxResults);
142
+
143
+ return scored.map(({ skill }) => skill);
144
+ }
145
+
146
+ /**
147
+ * 获取所有 Skill 的工具(扁平化)
148
+ */
149
+ collectAllTools(): Tool[] {
150
+ const tools: Tool[] = [];
151
+ for (const skill of this.items) {
152
+ tools.push(...skill.tools);
153
+ }
154
+ return tools;
155
+ }
156
+
157
+ /**
158
+ * 已注册 Skill 数量
159
+ */
160
+ get size(): number {
161
+ return this.items.length;
162
+ }
163
+
164
+ /**
165
+ * 简单的关键词匹配评分
166
+ */
167
+ #scoreSkill(skill: Skill, query: string): number {
168
+ const lowerQuery = query.toLowerCase();
169
+ let score = 0;
170
+
171
+ // 关键词精确匹配
172
+ if (skill.keywords) {
173
+ for (const kw of skill.keywords) {
174
+ if (lowerQuery.includes(kw.toLowerCase())) score += 1.0;
175
+ }
176
+ }
177
+
178
+ // 标签匹配
179
+ if (skill.tags) {
180
+ for (const tag of skill.tags) {
181
+ if (lowerQuery.includes(tag.toLowerCase())) score += 0.5;
182
+ }
183
+ }
184
+
185
+ // 名称匹配
186
+ if (lowerQuery.includes(skill.name.toLowerCase())) score += 0.3;
187
+
188
+ // 描述匹配(双向)
189
+ const lowerDesc = skill.description.toLowerCase();
190
+ if (lowerDesc.includes(lowerQuery)) score += 0.2;
191
+ if (lowerQuery.includes(lowerDesc)) score += 0.15;
192
+
193
+ // 工具名/描述匹配
194
+ for (const tool of skill.tools) {
195
+ if (lowerQuery.includes(tool.name.toLowerCase())) score += 0.4;
196
+ if (tool.description && lowerQuery.includes(tool.description.toLowerCase().slice(0, 10))) {
197
+ score += 0.1;
198
+ }
199
+ }
200
+
201
+ return score;
202
+ }
203
+
204
+ /**
205
+ * 序列化为 JSON
206
+ */
207
+ toJSON(pluginName?: string): FeatureJSON {
208
+ const list = pluginName ? this.getByPlugin(pluginName) : this.items;
209
+ return {
210
+ name: this.name,
211
+ icon: this.icon,
212
+ desc: this.desc,
213
+ count: list.length,
214
+ items: list.map(s => ({
215
+ name: s.name,
216
+ desc: s.description,
217
+ toolCount: s.tools.length,
218
+ keywords: s.keywords,
219
+ tags: s.tags,
220
+ })),
221
+ };
222
+ }
223
+
224
+ /**
225
+ * 提供给 Plugin.prototype 的扩展方法
226
+ */
227
+ get extensions() {
228
+ const feature = this;
229
+ return {
230
+ declareSkill(metadata: SkillMetadata) {
231
+ const plugin = getPlugin();
232
+ const pluginName = plugin.name;
233
+
234
+ // 收集该插件注册的工具
235
+ const toolService = plugin.root.inject('tool' as any) as any;
236
+ let tools: Tool[] = [];
237
+
238
+ if (toolService && typeof toolService.getToolsByPlugin === 'function') {
239
+ tools = toolService.getToolsByPlugin(pluginName);
240
+ } else {
241
+ // 回退:从插件本地工具获取
242
+ tools = plugin.getAllTools?.() || [];
243
+ }
244
+
245
+ // 聚合关键词:开发者声明 + 工具自带
246
+ const allKeywords = new Set<string>(metadata.keywords || []);
247
+ for (const tool of tools) {
248
+ if ((tool as any).keywords) {
249
+ for (const kw of (tool as any).keywords) {
250
+ allKeywords.add(kw);
251
+ }
252
+ }
253
+ }
254
+
255
+ // 聚合标签
256
+ const allTags = new Set<string>(metadata.tags || []);
257
+ for (const tool of tools) {
258
+ if (tool.tags) {
259
+ for (const tag of tool.tags) {
260
+ allTags.add(tag);
261
+ }
262
+ }
263
+ }
264
+
265
+ const skill: Skill = {
266
+ name: pluginName,
267
+ description: metadata.description,
268
+ tools,
269
+ keywords: Array.from(allKeywords),
270
+ tags: Array.from(allTags),
271
+ pluginName,
272
+ };
273
+
274
+ const dispose = feature.add(skill, pluginName);
275
+ plugin.recordFeatureContribution(feature.name, pluginName);
276
+ plugin.onDispose(dispose);
277
+ },
278
+ };
279
+ }
280
+ }