@zhin.js/agent 0.0.20 → 0.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 (116) hide show
  1. package/README.md +5 -2
  2. package/lib/cron-engine.d.ts +16 -1
  3. package/lib/cron-engine.d.ts.map +1 -1
  4. package/lib/cron-engine.js +47 -13
  5. package/lib/cron-engine.js.map +1 -1
  6. package/lib/discover-skills.d.ts +3 -1
  7. package/lib/discover-skills.d.ts.map +1 -1
  8. package/lib/discover-skills.js +7 -9
  9. package/lib/discover-skills.js.map +1 -1
  10. package/lib/discover-tools.d.ts +1 -6
  11. package/lib/discover-tools.d.ts.map +1 -1
  12. package/lib/discover-tools.js +2 -6
  13. package/lib/discover-tools.js.map +1 -1
  14. package/lib/index.d.ts +2 -4
  15. package/lib/index.d.ts.map +1 -1
  16. package/lib/index.js +1 -2
  17. package/lib/index.js.map +1 -1
  18. package/lib/init/create-zhin-agent.d.ts.map +1 -1
  19. package/lib/init/create-zhin-agent.js +58 -21
  20. package/lib/init/create-zhin-agent.js.map +1 -1
  21. package/lib/init/register-ai-trigger.d.ts.map +1 -1
  22. package/lib/init/register-ai-trigger.js +10 -3
  23. package/lib/init/register-ai-trigger.js.map +1 -1
  24. package/lib/init/register-builtin-tools.d.ts.map +1 -1
  25. package/lib/init/register-builtin-tools.js +46 -14
  26. package/lib/init/register-builtin-tools.js.map +1 -1
  27. package/lib/init/register-db-models.d.ts.map +1 -1
  28. package/lib/init/register-db-models.js +1 -3
  29. package/lib/init/register-db-models.js.map +1 -1
  30. package/lib/init/register-db-upgrade.d.ts.map +1 -1
  31. package/lib/init/register-db-upgrade.js +1 -8
  32. package/lib/init/register-db-upgrade.js.map +1 -1
  33. package/lib/init/register-management-tools.d.ts.map +1 -1
  34. package/lib/init/register-management-tools.js +33 -20
  35. package/lib/init/register-management-tools.js.map +1 -1
  36. package/lib/service.d.ts +4 -0
  37. package/lib/service.d.ts.map +1 -1
  38. package/lib/service.js +3 -8
  39. package/lib/service.js.map +1 -1
  40. package/lib/zhin-agent/builtin-tools.d.ts +0 -2
  41. package/lib/zhin-agent/builtin-tools.d.ts.map +1 -1
  42. package/lib/zhin-agent/builtin-tools.js +0 -55
  43. package/lib/zhin-agent/builtin-tools.js.map +1 -1
  44. package/lib/zhin-agent/config.d.ts +4 -1
  45. package/lib/zhin-agent/config.d.ts.map +1 -1
  46. package/lib/zhin-agent/config.js +2 -1
  47. package/lib/zhin-agent/config.js.map +1 -1
  48. package/lib/zhin-agent/index.d.ts +11 -6
  49. package/lib/zhin-agent/index.d.ts.map +1 -1
  50. package/lib/zhin-agent/index.js +147 -81
  51. package/lib/zhin-agent/index.js.map +1 -1
  52. package/lib/zhin-agent/prompt.d.ts.map +1 -1
  53. package/lib/zhin-agent/prompt.js +31 -76
  54. package/lib/zhin-agent/prompt.js.map +1 -1
  55. package/lib/zhin-agent/tool-collector.d.ts.map +1 -1
  56. package/lib/zhin-agent/tool-collector.js +7 -7
  57. package/lib/zhin-agent/tool-collector.js.map +1 -1
  58. package/package.json +7 -4
  59. package/CHANGELOG.md +0 -170
  60. package/lib/follow-up.d.ts +0 -131
  61. package/lib/follow-up.d.ts.map +0 -1
  62. package/lib/follow-up.js +0 -265
  63. package/lib/follow-up.js.map +0 -1
  64. package/src/agent.ts +0 -6
  65. package/src/bootstrap.ts +0 -309
  66. package/src/builtin-tools.ts +0 -958
  67. package/src/compaction.ts +0 -28
  68. package/src/context-manager.ts +0 -15
  69. package/src/conversation-memory.ts +0 -5
  70. package/src/cron-engine.ts +0 -338
  71. package/src/discover-agents.ts +0 -138
  72. package/src/discover-skills.ts +0 -325
  73. package/src/discover-tools.ts +0 -302
  74. package/src/discovery-utils.ts +0 -96
  75. package/src/file-policy.ts +0 -333
  76. package/src/follow-up.ts +0 -357
  77. package/src/hooks.ts +0 -223
  78. package/src/index.ts +0 -183
  79. package/src/init/create-zhin-agent.ts +0 -136
  80. package/src/init/register-ai-service.ts +0 -53
  81. package/src/init/register-ai-trigger.ts +0 -253
  82. package/src/init/register-builtin-tools.ts +0 -308
  83. package/src/init/register-db-models.ts +0 -31
  84. package/src/init/register-db-upgrade.ts +0 -77
  85. package/src/init/register-management-tools.ts +0 -71
  86. package/src/init/register-message-recorder.ts +0 -31
  87. package/src/init/register-tool-service.ts +0 -9
  88. package/src/init/shared-refs.ts +0 -20
  89. package/src/init/types.ts +0 -18
  90. package/src/init.ts +0 -50
  91. package/src/output.ts +0 -15
  92. package/src/rate-limiter.ts +0 -5
  93. package/src/service.ts +0 -224
  94. package/src/session.ts +0 -13
  95. package/src/storage.ts +0 -9
  96. package/src/subagent.ts +0 -209
  97. package/src/tone-detector.ts +0 -5
  98. package/src/tools.ts +0 -214
  99. package/src/user-profile.ts +0 -182
  100. package/src/zhin-agent/builtin-tools.ts +0 -247
  101. package/src/zhin-agent/config.ts +0 -121
  102. package/src/zhin-agent/exec-policy.ts +0 -285
  103. package/src/zhin-agent/index.ts +0 -559
  104. package/src/zhin-agent/prompt.ts +0 -305
  105. package/src/zhin-agent/tool-collector.ts +0 -249
  106. package/tests/ai/follow-up.test.ts +0 -175
  107. package/tests/ai/integration.test.ts +0 -582
  108. package/tests/ai/multimodal.test.ts +0 -106
  109. package/tests/ai/setup.ts +0 -186
  110. package/tests/ai/subagent.test.ts +0 -270
  111. package/tests/ai/tools-builtin.test.ts +0 -310
  112. package/tests/ai/user-profile.test.ts +0 -73
  113. package/tests/ai/zhin-agent.test.ts +0 -306
  114. package/tests/exec-policy.test.ts +0 -355
  115. package/tests/file-policy.test.ts +0 -405
  116. package/tsconfig.json +0 -22
@@ -1,308 +0,0 @@
1
- /**
2
- * Register built-in system tools (file/shell/web/schedule/memory/skill)
3
- * and workspace skills with hot-reload support.
4
- */
5
- import * as fs from 'fs';
6
- import * as os from 'os';
7
- import * as path from 'path';
8
- import { getPlugin, type Tool, type SkillFeature, type AgentPresetFeature } from '@zhin.js/core';
9
- import { createBuiltinTools } from '../builtin-tools.js';
10
- import { collectPluginSkillSearchRoots } from '../discovery-utils.js';
11
- import { discoverWorkspaceSkills, loadAlwaysSkillsContent, buildSkillsSummaryXML } from '../discover-skills.js';
12
- import { discoverWorkspaceAgents } from '../discover-agents.js';
13
- import { discoverWorkspaceTools, buildToolFromMeta } from '../discover-tools.js';
14
- import { resolveSkillInstructionMaxChars, DEFAULT_CONFIG } from '../zhin-agent/config.js';
15
- import { loadBootstrapFiles, buildContextFiles, buildBootstrapContextSection } from '../bootstrap.js';
16
- import { triggerAIHook, createAIHookEvent } from '../hooks.js';
17
- import { createCronTools } from '../cron-engine.js';
18
- import type { AIServiceRefs } from './shared-refs.js';
19
-
20
- export function registerBuiltinTools(refs: AIServiceRefs): void {
21
- const plugin = getPlugin();
22
- const { useContext, root, logger } = plugin;
23
-
24
- useContext('ai', 'tool', (ai, toolService) => {
25
- if (!ai || !toolService) return;
26
-
27
- const provider = ai.getProvider();
28
- const agentCfg = ai.getAgentConfig();
29
- const fullCfg = { ...DEFAULT_CONFIG, ...agentCfg } as Required<import('../zhin-agent/config.js').ZhinAgentConfig>;
30
- const modelName = provider.models[0] || '';
31
- const builtinTools = createBuiltinTools({
32
- plugin,
33
- skillInstructionMaxChars: resolveSkillInstructionMaxChars(fullCfg, modelName),
34
- pluginSkillRootsResolver: () => collectPluginSkillSearchRoots(root),
35
- skillFileLookup: (name: string) => {
36
- const skillFeature = root.inject?.('skill') as SkillFeature | undefined;
37
- return skillFeature?.get(name)?.filePath;
38
- },
39
- });
40
- const disposers: (() => void)[] = [];
41
- for (const tool of builtinTools) disposers.push(toolService.addTool(tool, root.name));
42
- const cronTools = createCronTools();
43
- for (const tool of cronTools) disposers.push(toolService.addTool(tool, root.name));
44
- logger.info(`Registered ${builtinTools.length} built-in + ${cronTools.length} cron tools`);
45
-
46
- let skillWatchers: fs.FSWatcher[] = [];
47
- let skillReloadDebounce: ReturnType<typeof setTimeout> | null = null;
48
- let toolReloadDebounce: ReturnType<typeof setTimeout> | null = null;
49
-
50
- async function syncWorkspaceSkills(): Promise<number> {
51
- const skillFeature = root.inject?.('skill') as SkillFeature | undefined;
52
- if (!skillFeature) return 0;
53
- const existing = skillFeature.getByPlugin(root.name);
54
- for (const s of existing) skillFeature.remove(s);
55
- const skills = await discoverWorkspaceSkills(root);
56
- if (skills.length > 0) {
57
- const allRegisteredTools = toolService.getAll();
58
- const toolNameIndex = new Map<string, Tool>();
59
- for (const t of allRegisteredTools) {
60
- toolNameIndex.set(t.name, t);
61
- const parts = t.name.split('_');
62
- if (parts.length === 2) toolNameIndex.set(`${parts[1]}_${parts[0]}`, t);
63
- }
64
- for (const s of skills) {
65
- const associatedTools: Tool[] = [];
66
- const toolNames = s.toolNames || [];
67
- for (const toolName of toolNames) {
68
- let tool = toolService.get(toolName) || toolNameIndex.get(toolName);
69
- if (tool) associatedTools.push(tool);
70
- }
71
- skillFeature.add({
72
- name: s.name,
73
- description: s.description,
74
- tools: associatedTools,
75
- keywords: s.keywords || [],
76
- tags: s.tags || [],
77
- pluginName: root.name,
78
- filePath: s.filePath,
79
- always: s.always,
80
- }, root.name);
81
- }
82
- }
83
- // Inject always-on skills content + XML summary into agent
84
- if (refs.zhinAgent) {
85
- const alwaysContent = await loadAlwaysSkillsContent(skills);
86
- const skillsXml = buildSkillsSummaryXML(skills);
87
- refs.zhinAgent.setActiveSkillsContext(alwaysContent);
88
- refs.zhinAgent.setSkillsSummaryXML(skillsXml);
89
- }
90
- return skills.length;
91
- }
92
-
93
- // 文件化 Tool 的 disposer(用于热重载时移除旧 tool)
94
- let toolFileDisposers: (() => void)[] = [];
95
-
96
- /**
97
- * Discover *.tool.md files and register them as tools.
98
- */
99
- async function syncWorkspaceTools(): Promise<number> {
100
- // 移除之前文件化注册的 tool
101
- for (const d of toolFileDisposers) d();
102
- toolFileDisposers = [];
103
-
104
- const toolMetas = await discoverWorkspaceTools(root);
105
- if (toolMetas.length === 0) return 0;
106
-
107
- let added = 0;
108
- for (const meta of toolMetas) {
109
- // 跳过已通过程序化方式注册的同名 tool
110
- if (toolService.get(meta.name)) {
111
- logger.debug(`Tool '${meta.name}' 已存在(程序化注册),跳过文件化版本`);
112
- continue;
113
- }
114
- const tool = await buildToolFromMeta(meta);
115
- if (!tool) continue;
116
- const dispose = toolService.addTool(tool, root.name);
117
- toolFileDisposers.push(dispose);
118
- added++;
119
- }
120
- return added;
121
- }
122
-
123
- /**
124
- * Discover *.agent.md files and register agent presets into AgentPresetFeature.
125
- */
126
- async function syncWorkspaceAgents(): Promise<number> {
127
- const agentPresetFeature = root.inject?.('agentPreset') as AgentPresetFeature | undefined;
128
- if (!agentPresetFeature) return 0;
129
-
130
- // Remove previously discovered presets for this plugin
131
- const existing = agentPresetFeature.getByPlugin(root.name);
132
- for (const p of existing) agentPresetFeature.remove(p);
133
-
134
- const agentMetas = await discoverWorkspaceAgents(root);
135
- if (agentMetas.length === 0) return 0;
136
-
137
- const allRegisteredTools = toolService.getAll();
138
- const toolNameIndex = new Map<string, import('@zhin.js/core').Tool>();
139
- for (const t of allRegisteredTools) {
140
- toolNameIndex.set(t.name, t);
141
- }
142
- let added = 0;
143
- for (const meta of agentMetas) {
144
- if (agentPresetFeature.get(meta.name)) continue;
145
- const associatedTools: import('@zhin.js/core').Tool[] = [];
146
- for (const toolName of meta.toolNames || []) {
147
- const tool = toolService.get(toolName) || toolNameIndex.get(toolName);
148
- if (tool) associatedTools.push(tool);
149
- }
150
- // Read body as systemPrompt
151
- let systemPrompt: string | undefined;
152
- try {
153
- const content = await fs.promises.readFile(meta.filePath, 'utf-8');
154
- const body = content.replace(/^---\s*\n[\s\S]*?\n---\s*(?:\n|$)/, '').trim();
155
- if (body) systemPrompt = body;
156
- } catch { /* ignore */ }
157
- agentPresetFeature.add({
158
- name: meta.name,
159
- description: meta.description,
160
- keywords: meta.keywords,
161
- tags: meta.tags,
162
- tools: associatedTools.length > 0 ? associatedTools : undefined,
163
- systemPrompt,
164
- model: meta.model,
165
- provider: meta.provider,
166
- maxIterations: meta.maxIterations,
167
- filePath: meta.filePath,
168
- }, root.name);
169
- added++;
170
- }
171
- return added;
172
- }
173
-
174
- (async () => {
175
- // Step 1: discover workspace skills
176
- try {
177
- const count = await syncWorkspaceSkills();
178
- const skillFeature = root.inject?.('skill') as SkillFeature | undefined;
179
- if (count > 0 && skillFeature) {
180
- logger.info(`Registered ${count} workspace skills`);
181
- }
182
- } catch (e: any) {
183
- logger.warn(`Failed to discover workspace skills: ${e.message}`);
184
- }
185
-
186
- // Step 1b: discover *.tool.md file-based tools
187
- try {
188
- const toolCount = await syncWorkspaceTools();
189
- if (toolCount > 0) {
190
- logger.info(`Registered ${toolCount} workspace file-based tools`);
191
- }
192
- } catch (e: any) {
193
- logger.warn(`Failed to discover workspace tools: ${e.message}`);
194
- }
195
-
196
- // Step 1c: discover *.agent.md agent presets
197
- try {
198
- const agentCount = await syncWorkspaceAgents();
199
- if (agentCount > 0) {
200
- logger.info(`Registered ${agentCount} workspace agent presets`);
201
- }
202
- } catch (e: any) {
203
- logger.debug(`Failed to discover workspace agents: ${e.message}`);
204
- }
205
-
206
- // Step 2: load bootstrap files
207
- const loadedFiles: string[] = [];
208
- try {
209
- const workspaceDir = process.cwd();
210
- const bootstrapFiles = await loadBootstrapFiles(workspaceDir);
211
- const contextFiles = buildContextFiles(bootstrapFiles);
212
-
213
- logger.debug(`Bootstrap files loaded (cwd: ${workspaceDir}): ${bootstrapFiles.map(f => f.name + (f.missing ? ' (missing)' : '')).join(', ')}`);
214
-
215
- const soulFile = contextFiles.find(f => f.path === 'SOUL.md');
216
- if (soulFile && refs.zhinAgent) loadedFiles.push('SOUL.md');
217
-
218
- const toolsFile = contextFiles.find(f => f.path === 'TOOLS.md');
219
- if (toolsFile) loadedFiles.push('TOOLS.md');
220
-
221
- const agentsFile = contextFiles.find(f => f.path === 'AGENTS.md');
222
- if (agentsFile) loadedFiles.push('AGENTS.md');
223
-
224
- if (loadedFiles.length > 0) {
225
- logger.info(`Loaded bootstrap: ${loadedFiles.join(', ')} → agent prompt`);
226
- }
227
-
228
- if (refs.zhinAgent && contextFiles.length > 0) {
229
- const contextSection = buildBootstrapContextSection(contextFiles);
230
- refs.zhinAgent.setBootstrapContext(contextSection);
231
- }
232
- } catch (e: any) {
233
- logger.debug(`Bootstrap files not loaded: ${e.message}`);
234
- }
235
-
236
- // Trigger agent:bootstrap hook
237
- const skillFeature2 = root.inject('skill') as SkillFeature | undefined;
238
- await triggerAIHook(createAIHookEvent('agent', 'bootstrap', undefined, {
239
- workspaceDir: process.cwd(),
240
- toolCount: builtinTools.length,
241
- skillCount: skillFeature2?.size ?? 0,
242
- bootstrapFiles: loadedFiles,
243
- }));
244
-
245
- // Hot-reload tool directories
246
- const workspaceToolDir = path.join(process.cwd(), 'tools');
247
- const onToolDirChange = () => {
248
- if (toolReloadDebounce) clearTimeout(toolReloadDebounce);
249
- toolReloadDebounce = setTimeout(async () => {
250
- toolReloadDebounce = null;
251
- try {
252
- const count = await syncWorkspaceTools();
253
- if (count >= 0) logger.info(`[Tool热重载] 已更新,工作区文件化Tool: ${count}`);
254
- } catch (e: any) {
255
- logger.warn(`[Tool热重载] 失败: ${e.message}`);
256
- }
257
- }, 400);
258
- };
259
- if (fs.existsSync(workspaceToolDir)) {
260
- try {
261
- const w = fs.watch(workspaceToolDir, { recursive: true }, onToolDirChange);
262
- skillWatchers.push(w);
263
- logger.debug(`[Tool热重载] 监听目录: ${workspaceToolDir}`);
264
- } catch (e: any) {
265
- logger.debug(`[Tool热重载] 无法监听 ${workspaceToolDir}: ${e.message}`);
266
- }
267
- }
268
-
269
- // Hot-reload skill directories
270
- const workspaceSkillDir = path.join(process.cwd(), 'skills');
271
- const localSkillDir = path.join(os.homedir(), '.zhin', 'skills');
272
- const onSkillDirChange = () => {
273
- if (skillReloadDebounce) clearTimeout(skillReloadDebounce);
274
- skillReloadDebounce = setTimeout(async () => {
275
- skillReloadDebounce = null;
276
- try {
277
- const count = await syncWorkspaceSkills();
278
- await triggerAIHook(createAIHookEvent('agent', 'skills-reloaded', undefined, { skillCount: count }));
279
- if (count >= 0) logger.info(`[技能热重载] 已更新,工作区技能: ${count}`);
280
- } catch (e: any) {
281
- logger.warn(`[技能热重载] 失败: ${e.message}`);
282
- }
283
- }, 400);
284
- };
285
- for (const dir of [workspaceSkillDir, localSkillDir]) {
286
- if (fs.existsSync(dir)) {
287
- try {
288
- const w = fs.watch(dir, { recursive: true }, onSkillDirChange);
289
- skillWatchers.push(w);
290
- logger.debug(`[技能热重载] 监听目录: ${dir}`);
291
- } catch (e: any) {
292
- logger.debug(`[技能热重载] 无法监听 ${dir}: ${e.message}`);
293
- }
294
- }
295
- }
296
- })();
297
-
298
- return () => {
299
- disposers.forEach(d => d());
300
- toolFileDisposers.forEach(d => d());
301
- toolFileDisposers = [];
302
- skillWatchers.forEach(w => w.close());
303
- skillWatchers = [];
304
- if (skillReloadDebounce) clearTimeout(skillReloadDebounce);
305
- if (toolReloadDebounce) clearTimeout(toolReloadDebounce);
306
- };
307
- });
308
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Define AI-related database models (7 tables).
3
- */
4
- import { getPlugin } from '@zhin.js/core';
5
- import { AI_SESSION_MODEL } from '@zhin.js/ai';
6
- import { CHAT_MESSAGE_MODEL, CONTEXT_SUMMARY_MODEL } from '@zhin.js/ai';
7
- import { AI_MESSAGE_MODEL, AI_SUMMARY_MODEL } from '@zhin.js/ai';
8
- import { AI_USER_PROFILE_MODEL } from '../user-profile.js';
9
- import { AI_FOLLOWUP_MODEL } from '../follow-up.js';
10
-
11
- export function registerDbModels(): void {
12
- const plugin = getPlugin();
13
- const { logger } = plugin;
14
-
15
- const defineModel = (plugin as unknown as Record<string, unknown>).defineModel as
16
- | ((name: string, def: Record<string, unknown>) => void)
17
- | undefined;
18
-
19
- if (typeof defineModel === 'function') {
20
- defineModel('chat_messages', CHAT_MESSAGE_MODEL);
21
- defineModel('context_summaries', CONTEXT_SUMMARY_MODEL);
22
- defineModel('ai_sessions', AI_SESSION_MODEL);
23
- defineModel('ai_messages', AI_MESSAGE_MODEL);
24
- defineModel('ai_summaries', AI_SUMMARY_MODEL);
25
- defineModel('ai_user_profiles', AI_USER_PROFILE_MODEL);
26
- defineModel('ai_followups', AI_FOLLOWUP_MODEL);
27
- logger.debug('AI database models registered (7 tables)');
28
- } else {
29
- logger.debug('defineModel not available, AI will use in-memory storage');
30
- }
31
- }
@@ -1,77 +0,0 @@
1
- /**
2
- * Upgrade AI components from in-memory to database storage when DB becomes ready.
3
- *
4
- * FIX: Replaced the previous `setTimeout(100)` race condition with
5
- * a proper `useContext('database', 'ai', ...)` dual-dependency wait.
6
- */
7
- import './types.js';
8
- import { getPlugin } from '@zhin.js/core';
9
- import type { AIConfig } from '@zhin.js/core';
10
- import { createDatabaseSessionManager } from '@zhin.js/ai';
11
- import { createContextManager } from '@zhin.js/ai';
12
- import type { AIServiceRefs } from './shared-refs.js';
13
-
14
- export function registerDbUpgrade(refs: AIServiceRefs): void {
15
- const plugin = getPlugin();
16
- const { useContext, root, logger } = plugin;
17
-
18
- useContext('database', 'ai', async (db: any, _ai) => {
19
- const aiService = refs.aiService;
20
- if (!aiService) return;
21
-
22
- const configService = root.inject('config');
23
- const appConfig =
24
- configService?.getPrimary<{ ai?: AIConfig }>() || {};
25
- const config = appConfig.ai || {};
26
-
27
- if (config.sessions?.useDatabase === false) return;
28
-
29
- try {
30
- const model = db.models?.get('ai_sessions');
31
- if (!model) return;
32
-
33
- const dbSession = createDatabaseSessionManager(
34
- model,
35
- aiService.getSessionConfig(),
36
- );
37
- aiService.setSessionManager(dbSession);
38
- if (refs.zhinAgent) refs.zhinAgent.setSessionManager(dbSession);
39
-
40
- const ctxCfg = aiService.getContextConfig();
41
- if (ctxCfg.enabled !== false) {
42
- const msgModel = db.models.get('chat_messages');
43
- const sumModel = db.models.get('context_summaries');
44
- if (msgModel && sumModel) {
45
- const ctxMgr = createContextManager(msgModel, sumModel, ctxCfg);
46
- aiService.setContextManager(ctxMgr);
47
- if (refs.zhinAgent) refs.zhinAgent.setContextManager(ctxMgr);
48
- }
49
- }
50
-
51
- if (refs.zhinAgent) {
52
- const aiMsgModel = db.models.get('ai_messages');
53
- const aiSumModel = db.models.get('ai_summaries');
54
- if (aiMsgModel && aiSumModel) {
55
- refs.zhinAgent.upgradeMemoryToDatabase(aiMsgModel, aiSumModel);
56
- }
57
-
58
- const profileModel = db.models.get('ai_user_profiles');
59
- if (profileModel) {
60
- refs.zhinAgent.upgradeProfilesToDatabase(profileModel);
61
- }
62
-
63
- const followUpModel = db.models.get('ai_followups');
64
- if (followUpModel) {
65
- refs.zhinAgent.upgradeFollowUpsToDatabase(followUpModel);
66
- refs.zhinAgent.restoreFollowUps().catch(e => {
67
- logger.warn('FollowUp restore failed:', e);
68
- });
69
- }
70
- }
71
-
72
- logger.debug('AI database storage activated (session, memory, profile, followup)');
73
- } catch (e) {
74
- logger.error('AI Session: database setup failed:', e);
75
- }
76
- });
77
- }
@@ -1,71 +0,0 @@
1
- /**
2
- * Register AI management tools (ai.models, ai.clear, ai.health).
3
- */
4
- import './types.js';
5
- import { getPlugin, Message, ZhinTool } from '@zhin.js/core';
6
- import { SessionManager } from '@zhin.js/ai';
7
-
8
- export function registerManagementTools(): void {
9
- const plugin = getPlugin();
10
- const { useContext, root, logger } = plugin;
11
-
12
- useContext('ai', 'tool', (ai, toolService) => {
13
- if (!ai || !toolService) return;
14
-
15
- const listModelsTool = new ZhinTool('ai_models')
16
- .desc('列出所有可用的 AI 模型')
17
- .keyword('模型', '可用模型', 'ai模型', 'model', 'models')
18
- .tag('ai', 'management')
19
- .execute(async () => {
20
- const models = await ai.listModels();
21
- return { providers: models.map(({ provider, models: ml }) => ({ name: provider, models: ml.slice(0, 10), total: ml.length })) };
22
- })
23
- .action(async () => {
24
- const models = await ai.listModels();
25
- let r = '🤖 可用模型:\n';
26
- for (const { provider, models: ml } of models) {
27
- r += `\n【${provider}】\n` + ml.slice(0, 5).map(m => ` • ${m}`).join('\n');
28
- if (ml.length > 5) r += `\n ... 还有 ${ml.length - 5} 个`;
29
- }
30
- return r;
31
- });
32
-
33
- const clearSessionTool = new ZhinTool('ai_clear')
34
- .desc('清除当前对话的历史记录')
35
- .keyword('清除', '清空', '重置', 'clear', 'reset')
36
- .tag('ai', 'session')
37
- .execute(async (_args, context) => {
38
- if (!context?.message) return { success: false, error: '无消息上下文' };
39
- const msg = context.message as Message;
40
- const sid = SessionManager.generateId(msg.$adapter, msg.$sender.id, msg.$channel?.id);
41
- await ai.sessions.reset(sid);
42
- return { success: true, message: '对话历史已清除' };
43
- })
44
- .action(async (message: Message) => {
45
- const sid = SessionManager.generateId(message.$adapter, message.$sender.id, message.$channel?.id);
46
- await ai.sessions.reset(sid);
47
- return '✅ 对话历史已清除';
48
- });
49
-
50
- const healthCheckTool = new ZhinTool('ai_health')
51
- .desc('检查 AI 服务的健康状态')
52
- .keyword('健康', '状态', '检查', 'health', 'status')
53
- .tag('ai', 'management')
54
- .execute(async () => {
55
- const h = await ai.healthCheck();
56
- return { providers: Object.entries(h).map(([n, ok]) => ({ name: n, healthy: ok })) };
57
- })
58
- .action(async () => {
59
- const h = await ai.healthCheck();
60
- return ['🏥 AI 服务健康状态:'].concat(
61
- Object.entries(h).map(([p, ok]) => ` ${ok ? '✅' : '❌'} ${p}`),
62
- ).join('\n');
63
- });
64
-
65
- const tools = [listModelsTool, clearSessionTool, healthCheckTool];
66
- const disposers: (() => void)[] = [];
67
- for (const tool of tools) disposers.push(toolService.addTool(tool, root.name));
68
- logger.debug(`Registered ${tools.length} AI management tools`);
69
- return () => disposers.forEach(d => d());
70
- });
71
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Register middleware that records messages to the context manager.
3
- */
4
- import { getPlugin, Message } from '@zhin.js/core';
5
- import type { MessageRecord } from '@zhin.js/ai';
6
- import type { AIServiceRefs } from './shared-refs.js';
7
-
8
- export function registerMessageRecorder(refs: AIServiceRefs): void {
9
- const plugin = getPlugin();
10
- const { root } = plugin;
11
-
12
- root.addMiddleware(async (message: Message, next: () => Promise<void>) => {
13
- await next();
14
- if (refs.aiService?.contextManager) {
15
- const record: MessageRecord = {
16
- platform: message.$adapter,
17
- scene_id: message.$channel?.id || message.$sender.id,
18
- scene_type: message.$channel?.type || 'private',
19
- scene_name: (message.$channel as { name?: string })?.name || '',
20
- sender_id: message.$sender.id,
21
- sender_name: message.$sender.name || message.$sender.id,
22
- message:
23
- typeof message.$raw === 'string'
24
- ? message.$raw
25
- : JSON.stringify(message.$raw),
26
- time: message.$timestamp || Date.now(),
27
- };
28
- refs.aiService.contextManager.recordMessage(record).catch(() => {});
29
- }
30
- });
31
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Register ToolFeature into the plugin system.
3
- */
4
- import { getPlugin, ToolFeature } from '@zhin.js/core';
5
-
6
- export function registerToolService(): void {
7
- const plugin = getPlugin();
8
- plugin.provide(new ToolFeature());
9
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Shared mutable references between init sub-modules.
3
- *
4
- * These refs allow the split modules to coordinate without passing
5
- * the instances through function parameters everywhere.
6
- */
7
- import type { AIService } from '../service.js';
8
- import type { ZhinAgent } from '../zhin-agent/index.js';
9
-
10
- export interface AIServiceRefs {
11
- aiService: AIService | null;
12
- zhinAgent: ZhinAgent | null;
13
- }
14
-
15
- export function createRefs(): AIServiceRefs {
16
- return {
17
- aiService: null,
18
- zhinAgent: null,
19
- };
20
- }
package/src/init/types.ts DELETED
@@ -1,18 +0,0 @@
1
- /**
2
- * Consolidated type augmentation for the agent package.
3
- * This ensures all init sub-modules can use typed inject/useContext
4
- * without `as any` casts.
5
- */
6
-
7
- import type { AIService } from '../service.js';
8
-
9
- // Re-export the augmentation so it is applied when this file is imported
10
- declare module '@zhin.js/core' {
11
- namespace Plugin {
12
- interface Contexts {
13
- ai: AIService;
14
- }
15
- }
16
- }
17
-
18
- export {};
package/src/init.ts DELETED
@@ -1,50 +0,0 @@
1
- /**
2
- * AI 模块初始化
3
- *
4
- * 将 AI 服务注册到 Zhin 插件系统中。
5
- * 每个子职责拆分到 init/ 下的独立模块:
6
- * - register-tool-service — ToolFeature 注册
7
- * - register-db-models — 数据库模型定义
8
- * - register-ai-service — AIService context
9
- * - create-zhin-agent — ZhinAgent 全局大脑 + 子系统
10
- * - register-ai-trigger — AI 触发处理器
11
- * - register-db-upgrade — 数据库存储升级(无竞态条件)
12
- * - register-message-recorder — 消息记录中间件
13
- * - register-management-tools — AI 管理工具
14
- * - register-builtin-tools — 内置系统工具 + 工作区技能
15
- */
16
-
17
- import './init/types.js';
18
- import { createRefs } from './init/shared-refs.js';
19
- import { registerToolService } from './init/register-tool-service.js';
20
- import { registerDbModels } from './init/register-db-models.js';
21
- import { registerAIService } from './init/register-ai-service.js';
22
- import { createZhinAgentContext } from './init/create-zhin-agent.js';
23
- import { registerAITrigger } from './init/register-ai-trigger.js';
24
- import { registerDbUpgrade } from './init/register-db-upgrade.js';
25
- import { registerMessageRecorder } from './init/register-message-recorder.js';
26
- import { registerManagementTools } from './init/register-management-tools.js';
27
- import { registerBuiltinTools } from './init/register-builtin-tools.js';
28
-
29
- /**
30
- * 初始化 AI 模块
31
- *
32
- * 在 setup.ts 中调用:
33
- * ```ts
34
- * import { initAgentModule } from '@zhin.js/agent';
35
- * initAgentModule();
36
- * ```
37
- */
38
- export function initAgentModule(): void {
39
- const refs = createRefs();
40
-
41
- registerToolService();
42
- registerDbModels();
43
- registerAIService(refs);
44
- createZhinAgentContext(refs);
45
- registerAITrigger(refs);
46
- registerDbUpgrade(refs);
47
- registerMessageRecorder(refs);
48
- registerManagementTools();
49
- registerBuiltinTools(refs);
50
- }
package/src/output.ts DELETED
@@ -1,15 +0,0 @@
1
- /**
2
- * Re-export from @zhin.js/ai for backward compatibility.
3
- */
4
- export { parseOutput, renderToPlainText, renderToSatori } from '@zhin.js/ai';
5
- export type {
6
- TextElement,
7
- ImageElement,
8
- AudioElement,
9
- VideoElement,
10
- CardField,
11
- CardButton,
12
- CardElement,
13
- FileElement,
14
- OutputElement,
15
- } from '@zhin.js/ai';
@@ -1,5 +0,0 @@
1
- /**
2
- * Re-export from @zhin.js/ai for backward compatibility.
3
- */
4
- export { RateLimiter } from '@zhin.js/ai';
5
- export type { RateLimitConfig, RateLimitResult } from '@zhin.js/ai';