foliko 1.1.93 → 2.0.1

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 (212) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CLAUDE.md +56 -30
  3. package/REFACTORING_PLAN.md +645 -0
  4. package/docs/architecture.md +131 -0
  5. package/docs/migration.md +57 -0
  6. package/docs/public-api.md +138 -0
  7. package/docs/usage.md +385 -0
  8. package/examples/ambient-example.js +20 -137
  9. package/examples/basic.js +21 -48
  10. package/examples/bootstrap.js +16 -74
  11. package/examples/mcp-example.js +6 -29
  12. package/examples/skill-example.js +6 -19
  13. package/examples/workflow.js +8 -56
  14. package/package.json +8 -4
  15. package/plugins/README.md +49 -0
  16. package/plugins/{ambient-agent → ambient}/EventWatcher.js +1 -1
  17. package/plugins/{ambient-agent → ambient}/ExplorerLoop.js +3 -3
  18. package/plugins/{ambient-agent → ambient}/GoalManager.js +2 -2
  19. package/plugins/ambient/README.md +14 -0
  20. package/plugins/{ambient-agent → ambient}/Reflector.js +1 -1
  21. package/plugins/{ambient-agent → ambient}/StateStore.js +1 -1
  22. package/plugins/{ambient-agent → ambient}/index.js +2 -2
  23. package/plugins/{ai-plugin.js → core/ai/index.js} +14 -30
  24. package/plugins/{audit-plugin.js → core/audit/index.js} +3 -30
  25. package/plugins/{coordinator-plugin.js → core/coordinator/index.js} +3 -35
  26. package/plugins/core/default/bootstrap.js +224 -0
  27. package/plugins/core/default/config.js +222 -0
  28. package/plugins/core/default/index.js +58 -0
  29. package/plugins/core/mcp/index.js +1 -0
  30. package/plugins/{python-plugin-loader.js → core/python-loader/index.js} +7 -187
  31. package/plugins/{rules-plugin.js → core/rules/index.js} +121 -64
  32. package/plugins/{scheduler-plugin.js → core/scheduler/index.js} +12 -114
  33. package/plugins/{session-plugin.js → core/session/index.js} +9 -73
  34. package/{src/capabilities/skill-manager.js → plugins/core/skill-manager/index.js} +64 -18
  35. package/plugins/{storage-plugin.js → core/storage/index.js} +5 -29
  36. package/plugins/{subagent-plugin.js → core/sub-agent/index.js} +10 -171
  37. package/plugins/{think-plugin.js → core/think/index.js} +24 -91
  38. package/{src/capabilities/workflow-engine.js → plugins/core/workflow/index.js} +87 -85
  39. package/plugins/default-plugins.js +6 -720
  40. package/plugins/{data-splitter-plugin.js → executors/data-splitter/index.js} +9 -83
  41. package/plugins/{extension-executor-plugin.js → executors/extension/index.js} +13 -97
  42. package/plugins/{python-executor-plugin.js → executors/python/index.js} +6 -31
  43. package/plugins/{shell-executor-plugin.js → executors/shell/index.js} +2 -5
  44. package/plugins/install/README.md +9 -0
  45. package/plugins/{install-plugin.js → install/index.js} +3 -3
  46. package/plugins/{file-system-plugin.js → io/file-system/index.js} +34 -236
  47. package/plugins/{web-plugin.js → io/web/index.js} +11 -113
  48. package/plugins/memory/README.md +13 -0
  49. package/plugins/{memory-plugin.js → memory/index.js} +4 -18
  50. package/plugins/messaging/email/README.md +19 -0
  51. package/plugins/{email → messaging/email}/index.js +3 -3
  52. package/plugins/{feishu-plugin.js → messaging/feishu/index.js} +4 -4
  53. package/plugins/{qq-plugin.js → messaging/qq/index.js} +6 -17
  54. package/plugins/{telegram-plugin.js → messaging/telegram/index.js} +4 -4
  55. package/plugins/{weixin-plugin.js → messaging/weixin/index.js} +16 -16
  56. package/plugins/{plugin-manager-plugin.js → plugin-manager/index.js} +36 -180
  57. package/plugins/{tools-plugin.js → tools/index.js} +68 -116
  58. package/plugins/trading/README.md +15 -0
  59. package/plugins/{gate-trading.js → trading/index.js} +8 -8
  60. package/{examples → sandbox}/test-concurrent-chat.js +2 -2
  61. package/{examples → sandbox}/test-long-chat.js +2 -2
  62. package/{examples → sandbox}/test-session-chat.js +2 -2
  63. package/{examples → sandbox}/test-web-plugin.js +1 -1
  64. package/{examples → sandbox}/test-weixin-feishu.js +2 -2
  65. package/src/agent/base.js +56 -0
  66. package/src/{core/agent-chat.js → agent/chat.js} +11 -11
  67. package/src/{core/coordinator-manager.js → agent/coordinator.js} +3 -3
  68. package/src/agent/index.js +111 -0
  69. package/src/agent/main.js +337 -0
  70. package/src/agent/prompt.js +78 -0
  71. package/src/agent/sub.js +198 -0
  72. package/src/agent/worker.js +104 -0
  73. package/{cli/bin/foliko.js → src/cli/bin.js} +1 -1
  74. package/{cli/src → src/cli}/commands/chat.js +25 -21
  75. package/{cli/src → src/cli}/index.js +1 -0
  76. package/{cli/src → src/cli}/ui/chat-ui-old.js +40 -178
  77. package/{cli/src → src/cli}/ui/chat-ui.js +3 -3
  78. package/{cli/src → src/cli}/ui/components/footer-bar.js +1 -1
  79. package/src/common/errors.js +402 -0
  80. package/src/{utils → common}/logger.js +33 -0
  81. package/src/{utils/chat-queue.js → common/queue.js} +2 -2
  82. package/src/config/plugin-config.js +50 -0
  83. package/src/context/agent.js +32 -0
  84. package/src/context/compaction-prompts.js +170 -0
  85. package/src/context/compaction-utils.js +191 -0
  86. package/src/context/compressor.js +413 -0
  87. package/src/context/index.js +9 -0
  88. package/src/{core/context-manager.js → context/manager.js} +1 -1
  89. package/src/context/request.js +50 -0
  90. package/src/context/session.js +33 -0
  91. package/src/context/storage.js +30 -0
  92. package/src/executors/mcp-client.js +153 -0
  93. package/src/executors/mcp-desc.js +236 -0
  94. package/src/executors/mcp-executor.js +91 -956
  95. package/src/{core → framework}/command-registry.js +1 -1
  96. package/src/framework/framework.js +300 -0
  97. package/src/framework/index.js +18 -0
  98. package/src/framework/lifecycle.js +203 -0
  99. package/src/framework/loader.js +78 -0
  100. package/src/framework/registry.js +86 -0
  101. package/src/{core/ui-extension-context.js → framework/ui-extension.js} +1 -1
  102. package/src/index.js +130 -15
  103. package/src/llm/index.js +26 -0
  104. package/src/llm/provider.js +212 -0
  105. package/src/llm/registry.js +11 -0
  106. package/src/{core/token-counter.js → llm/tokens.js} +4 -37
  107. package/src/{core/plugin-base.js → plugin/base.js} +10 -136
  108. package/src/plugin/index.js +14 -0
  109. package/src/plugin/loader.js +101 -0
  110. package/src/plugin/manager.js +484 -0
  111. package/src/{core → session}/branch-summary-auto.js +2 -2
  112. package/src/{core/chat-session.js → session/chat.js} +2 -2
  113. package/src/session/index.js +7 -0
  114. package/src/{core/session-manager.js → session/session.js} +2 -2
  115. package/src/session/ttl.js +92 -0
  116. package/src/{core/jsonl-storage.js → storage/jsonl.js} +1 -1
  117. package/src/tool/executor.js +85 -0
  118. package/src/tool/index.js +15 -0
  119. package/src/tool/registry.js +143 -0
  120. package/src/{core/tool-router.js → tool/router.js} +17 -124
  121. package/src/tool/schema.js +108 -0
  122. package/src/utils/data-splitter.js +1 -1
  123. package/src/utils/download.js +1 -1
  124. package/src/utils/index.js +6 -6
  125. package/src/utils/message-validator.js +1 -1
  126. package/tests/core/context-storage.test.js +46 -0
  127. package/tests/core/llm.test.js +54 -0
  128. package/tests/core/plugin.test.js +42 -0
  129. package/tests/core/tool.test.js +60 -0
  130. package/tests/setup.js +10 -0
  131. package/tests/smoke.test.js +58 -0
  132. package/vitest.config.js +9 -0
  133. package/cli/src/daemon.js +0 -149
  134. package/docs/CONTEXT_DESIGN.md +0 -1596
  135. package/docs/ai-sdk-optimization.md +0 -655
  136. package/docs/features.md +0 -120
  137. package/docs/qq-bot.md +0 -976
  138. package/docs/quick-reference.md +0 -160
  139. package/docs/user-manual.md +0 -1391
  140. package/images/geometric_shapes.jpg +0 -0
  141. package/images/sunset_mountain_lake.jpg +0 -0
  142. package/skills/poster-guide/SKILL.md +0 -792
  143. package/src/capabilities/index.js +0 -11
  144. package/src/core/agent.js +0 -808
  145. package/src/core/context-compressor.js +0 -959
  146. package/src/core/enhanced-context-compressor.js +0 -210
  147. package/src/core/framework.js +0 -1422
  148. package/src/core/index.js +0 -30
  149. package/src/core/plugin-manager.js +0 -961
  150. package/src/core/provider-registry.js +0 -159
  151. package/src/core/provider.js +0 -156
  152. package/src/core/request-context.js +0 -98
  153. package/src/core/subagent.js +0 -442
  154. package/src/core/system-prompt-builder.js +0 -120
  155. package/src/core/tool-executor.js +0 -202
  156. package/src/core/tool-registry.js +0 -517
  157. package/src/core/worker-agent.js +0 -192
  158. package/src/executors/executor-base.js +0 -58
  159. package/src/utils/error-boundary.js +0 -363
  160. package/src/utils/error.js +0 -374
  161. package/system.md +0 -1645
  162. package/website_v2/README.md +0 -57
  163. package/website_v2/SPEC.md +0 -1
  164. package/website_v2/docs/api.html +0 -128
  165. package/website_v2/docs/configuration.html +0 -147
  166. package/website_v2/docs/plugin-development.html +0 -129
  167. package/website_v2/docs/project-structure.html +0 -89
  168. package/website_v2/docs/skill-development.html +0 -85
  169. package/website_v2/index.html +0 -489
  170. package/website_v2/scripts/main.js +0 -93
  171. package/website_v2/styles/animations.css +0 -8
  172. package/website_v2/styles/docs.css +0 -83
  173. package/website_v2/styles/main.css +0 -417
  174. package/xhs_auth.json +0 -268
  175. package//346/265/267/346/212/245/346/217/222/344/273/266.md +0 -621
  176. /package/plugins/{ambient-agent → ambient}/constants.js +0 -0
  177. /package/plugins/{email → messaging/email}/constants.js +0 -0
  178. /package/plugins/{email → messaging/email}/handlers.js +0 -0
  179. /package/plugins/{email → messaging/email}/monitor.js +0 -0
  180. /package/plugins/{email → messaging/email}/parser.js +0 -0
  181. /package/plugins/{email → messaging/email}/reply.js +0 -0
  182. /package/plugins/{email → messaging/email}/utils.js +0 -0
  183. /package/{examples → sandbox}/test-chat.js +0 -0
  184. /package/{examples → sandbox}/test-mcp.js +0 -0
  185. /package/{examples → sandbox}/test-reload.js +0 -0
  186. /package/{examples → sandbox}/test-telegram.js +0 -0
  187. /package/{examples → sandbox}/test-tg-bot.js +0 -0
  188. /package/{examples → sandbox}/test-tg-simple.js +0 -0
  189. /package/{examples → sandbox}/test-tg.js +0 -0
  190. /package/{examples → sandbox}/test-think.js +0 -0
  191. /package/src/{core/sub-agent-config.js → agent/sub-config.js} +0 -0
  192. /package/{cli/src → src/cli}/commands/daemon.js +0 -0
  193. /package/{cli/src → src/cli}/commands/list.js +0 -0
  194. /package/{cli/src → src/cli}/commands/plugin.js +0 -0
  195. /package/{cli/src → src/cli}/ui/components/agent-mention-provider.js +0 -0
  196. /package/{cli/src → src/cli}/ui/components/chained-autocomplete-provider.js +0 -0
  197. /package/{cli/src → src/cli}/ui/components/message-bubble.js +0 -0
  198. /package/{cli/src → src/cli}/ui/components/status-bar.js +0 -0
  199. /package/{cli/src → src/cli}/utils/ansi.js +0 -0
  200. /package/{cli/src → src/cli}/utils/config.js +0 -0
  201. /package/{cli/src → src/cli}/utils/markdown.js +0 -0
  202. /package/{cli/src → src/cli}/utils/plugin-config.js +0 -0
  203. /package/{cli/src → src/cli}/utils/render-diff.js +0 -0
  204. /package/src/{utils/circuit-breaker.js → common/circuit.js} +0 -0
  205. /package/src/{core → common}/constants.js +0 -0
  206. /package/src/{utils/edit-diff.js → common/diff.js} +0 -0
  207. /package/src/{utils/event-emitter.js → common/events.js} +0 -0
  208. /package/src/{utils → common}/id.js +0 -0
  209. /package/src/{utils → common}/retry.js +0 -0
  210. /package/src/{core/notification-manager.js → notification/manager.js} +0 -0
  211. /package/src/{core/session-entry.js → session/entry.js} +0 -0
  212. /package/src/{core/storage-manager.js → storage/manager.js} +0 -0
package/src/core/agent.js DELETED
@@ -1,808 +0,0 @@
1
- /**
2
- * Agent 类
3
- * 负责对话和推理
4
- */
5
-
6
- const { EventEmitter } = require('../utils/event-emitter');
7
- const { AgentChatHandler } = require('./agent-chat');
8
- const { SystemPromptBuilder } = require('./system-prompt-builder');
9
- const { NotificationManager } = require('./notification-manager');
10
- const { Logger, LOG_LEVELS } = require('../utils/logger');
11
- const os = require('os');
12
- const {
13
- PROMPT_PRIORITY,
14
- DEFAULT_MAX_OUTPUT_TOKENS,
15
- DEFAULT_TEMPERATURE,
16
- } = require('./constants');
17
-
18
- /**
19
- * Agent 配置常量
20
- */
21
- const AGENT_CONFIG = {
22
- MAX_OUTPUT_TOKENS: DEFAULT_MAX_OUTPUT_TOKENS,
23
- TEMPERATURE: DEFAULT_TEMPERATURE,
24
- MAX_NOTIFICATIONS: 5,
25
- CAPABILITY_MAX_LENGTH: 50,
26
- CAPABILITY_MAX_PARTS: 3,
27
- MAX_RETRIES: 3,
28
- };
29
-
30
- // 模块级 logger
31
- const _agentLogger = new Logger({ namespace: 'agent', level: LOG_LEVELS.INFO });
32
- const logger = {
33
- info: (ctx, msg, data) => _agentLogger.info(`[${ctx}] ${msg}`, data !== undefined ? data : ''),
34
- warn: (ctx, msg, data) => _agentLogger.warn(`[${ctx}] ${msg}`, data !== undefined ? data : ''),
35
- error: (ctx, msg, data) => _agentLogger.error(`[${ctx}] ${msg}`, data !== undefined ? data : ''),
36
- debug: (ctx, msg, data) => _agentLogger.debug(`[${ctx}] ${msg}`, data !== undefined ? data : ''),
37
- };
38
-
39
- class Agent extends EventEmitter {
40
- /**
41
- * @param {Framework} framework - 框架实例
42
- * @param {Object} config - 配置
43
- * @param {string} [config.name] - Agent 名称
44
- * @param {string} [config.systemPrompt] - 系统提示
45
- * @param {string} [config.sharedPrompt] - 共享提示模板,支持 {{VAR}} 占位符
46
- * @param {Object} [config.metadata] - 元数据,注入到 sharedPrompt
47
- * @param {boolean} [config.enableToolRouting=true] - 是否启用工具路由
48
- */
49
- constructor(framework, config = {}) {
50
- super();
51
-
52
- this.framework = framework;
53
- this.config = config;
54
-
55
- this.name = config.name || 'Agent';
56
- this.model = config.model || 'deepseek-chat';
57
- this.apiKey = config.apiKey;
58
- this.baseURL = config.baseURL;
59
- this.provider = config.provider || 'deepseek';
60
- this.providerOptions = {
61
- ...config.providerOptions,
62
- maxOutputTokens: config.providerOptions?.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS,
63
- temperature: config.providerOptions?.temperature ?? DEFAULT_TEMPERATURE,
64
- };
65
- // 原始 system prompt
66
- this._originalPrompt =
67
- config.systemPrompt ||
68
- '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。';
69
-
70
- // 共享提示模板
71
- this._sharedPrompt = config.sharedPrompt || '';
72
-
73
- // 元数据
74
- const metadata = config.metadata || {};
75
- this._metadata = new Map(Object.entries(metadata));
76
-
77
- this._chatHandler = null;
78
- this._tools = new Map();
79
- this._skipSyncTools = config.skipSyncTools || false;
80
- this._status = 'idle';
81
-
82
- // 子Agent管理
83
- this._subAgents = new Map();
84
-
85
- // System prompt 构建器
86
- this._systemPromptBuilder = new SystemPromptBuilder();
87
- this._registerDefaultPromptParts();
88
-
89
- // 处理后的 system prompt (带上下文)
90
- this.systemPrompt = this._buildSystemPrompt();
91
-
92
- // 通知管理器
93
- this._notificationManager = new NotificationManager(framework);
94
-
95
- // 初始化聊天处理器
96
- this._initChatHandler();
97
-
98
- // logger.info('Agent', `Agent "${this.name}" 初始化完成`);
99
- }
100
-
101
- /**
102
- * 注册默认的系统提示词部分
103
- * @private
104
- */
105
- _registerDefaultPromptParts() {
106
- // 1. 原始 system prompt (Agent 内部)
107
- this._systemPromptBuilder.register(
108
- 'original-prompt',
109
- PROMPT_PRIORITY.ORIGINAL_PROMPT,
110
- () => this._originalPrompt
111
- );
112
-
113
- // 2. 共享提示模板 (Agent 内部)
114
- this._systemPromptBuilder.register('shared-prompt', PROMPT_PRIORITY.SHARED_PROMPT, () => {
115
- if (this._sharedPrompt) {
116
- return this._replacePlaceholders(this._sharedPrompt);
117
- }
118
- return null;
119
- });
120
-
121
- // 3. 日期时间(框架基础设施)
122
- this._systemPromptBuilder.register('datetime', PROMPT_PRIORITY.DATETIME, () => {
123
- const now = new Date();
124
- const timeStr = now.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
125
- const dateStr = now.toLocaleDateString('zh-CN', {
126
- timeZone: 'Asia/Shanghai',
127
- weekday: 'long',
128
- });
129
- return `【当前时间】${timeStr}(${dateStr})`;
130
- });
131
-
132
- // 4. 元数据 (Agent 内部)
133
- this._systemPromptBuilder.register('metadata', PROMPT_PRIORITY.METADATA, () => {
134
- if (this._metadata.size === 0) {
135
- return null;
136
- }
137
- const metaParts = ['【元数据】'];
138
- for (const [key, value] of this._metadata) {
139
- if (typeof value === 'object') {
140
- metaParts.push(`- ${key}: ${JSON.stringify(value)}`);
141
- } else {
142
- metaParts.push(`- ${key}: ${value}`);
143
- }
144
- }
145
- return metaParts.join('\n');
146
- });
147
-
148
- // 5. 技能列表(已迁移到 skill-manager,通过 registerPromptPart 注册)
149
-
150
- // 6. 子Agent列表(已迁移到 subagent-plugin,通过 registerPromptPart 注册)
151
-
152
- // 7. 系统能力(由框架在 bootstrap 时注册)
153
- this._systemPromptBuilder.register('capabilities', PROMPT_PRIORITY.CAPABILITIES, () =>
154
- this._buildCapabilitiesDescription()
155
- );
156
-
157
- // 8. 扩展工具列表(已迁移到 extension-executor-plugin,通过 registerPromptPart 注册)
158
-
159
- // 9. 工具调用核心规则(已迁移到 tools-plugin,通过 registerPromptPart 注册)
160
- }
161
-
162
- /**
163
- * 获取元数据值
164
- */
165
- _getMetadataValue(key) {
166
- // 优先从 metadata 获取
167
- if (this._metadata.has(key)) {
168
- return this._metadata.get(key);
169
- }
170
-
171
- // 内置变量
172
- switch (key) {
173
- case 'WORK_DIR':
174
- case 'CWD':
175
- return this.framework?.getCwd?.() ?? process.cwd();
176
- case 'HOME_DIR':
177
- return os.homedir();
178
- case 'HOST_NAME':
179
- return os.hostname();
180
- case 'PLATFORM':
181
- return process.platform;
182
- case 'TIME':
183
- return new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
184
- case 'DATE':
185
- return new Date().toISOString().split('T')[0];
186
- default:
187
- return `{{${key}}}`;
188
- }
189
- }
190
-
191
- /**
192
- * 替换 sharedPrompt 中的占位符
193
- */
194
- _replacePlaceholders(template) {
195
- return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
196
- return this._getMetadataValue(key);
197
- });
198
- }
199
-
200
-
201
-
202
- /**
203
- * 构建系统能力描述
204
- */
205
- _buildCapabilitiesDescription() {
206
- const plugins = this.framework.pluginManager.getAll();
207
- if (!plugins || plugins.length === 0) {
208
- return '';
209
- }
210
-
211
- // 过滤出有描述的关键插件(排除内部插件)
212
- const keyPlugins = plugins.filter((p) => {
213
- const name = p.name;
214
- // 排除默认配置插件和内部插件
215
- return name !== 'defaults' && name !== 'agent';
216
- });
217
-
218
- if (keyPlugins.length === 0) {
219
- return '';
220
- }
221
-
222
- // 使用数组收集 + join 优化字符串拼接
223
- const lines = ['## 系统能力', ''];
224
- keyPlugins.forEach((plugin, index) => {
225
- const name = plugin.instance?.name || plugin.name || 'unknown';
226
- const description = plugin.instance?.description || '无描述';
227
- lines.push(`${index + 1}. **${name}**:${description}`);
228
- });
229
-
230
- return lines.join('\n');
231
- }
232
-
233
-
234
-
235
-
236
-
237
- /**
238
- * 递归提取字段类型信息
239
- * 处理 ZodOptional、ZodUnion、ZodArray 等复杂类型
240
- * @param {Object} field - Zod schema 字段
241
- * @returns {{ type: string, isOptional: boolean, description: string }}
242
- */
243
- _extractFieldType(field) {
244
- if (!field) {
245
- return { type: 'unknown', isOptional: false, description: '' };
246
- }
247
-
248
- const typeName = field._def?.typeName || field.constructor?.name || '';
249
- let description = field.description || field._def?.description || '';
250
-
251
- switch (typeName) {
252
- case 'ZodOptional': {
253
- const inner = field._def?.innerType;
254
- if (!inner) return { type: 'optional', isOptional: true, description };
255
- const innerInfo = this._extractFieldType(inner);
256
- return {
257
- type: innerInfo.type,
258
- isOptional: true,
259
- description: description || innerInfo.description,
260
- };
261
- }
262
- case 'ZodUnion': {
263
- if (!field._def?.options) return { type: 'union', isOptional: false, description };
264
- const types = field._def.options.map((opt) => this._extractFieldType(opt).type);
265
- return { type: `union(${types.join(' | ')})`, isOptional: false, description };
266
- }
267
- case 'ZodArray': {
268
- if (!field._def?.type) return { type: 'array', isOptional: false, description };
269
- const innerInfo = this._extractFieldType(field._def.type);
270
- return { type: `${innerInfo.type}[]`, isOptional: false, description };
271
- }
272
- case 'ZodObject': {
273
- if (!field._def?.shape) return { type: 'object', isOptional: false, description };
274
- const props = Object.keys(field._def.shape()).join(', ');
275
- return { type: `object{${props}}`, isOptional: false, description };
276
- }
277
- case 'ZodString':
278
- return { type: 'string', isOptional: false, description };
279
- case 'ZodNumber':
280
- return { type: 'number', isOptional: false, description };
281
- case 'ZodBoolean':
282
- return { type: 'boolean', isOptional: false, description };
283
- case 'ZodEnum': {
284
- const values = field._def?.values;
285
- if (!values) return { type: 'enum', isOptional: false, description };
286
- return {
287
- type: values.map((v) => `"${v}"`).join(' | '),
288
- isOptional: false,
289
- description,
290
- };
291
- }
292
- case 'ZodRecord': {
293
- const keyType = this._extractFieldType(field._def?.keyType);
294
- const valueType = this._extractFieldType(field._def?.valueType);
295
- return {
296
- type: `record<${keyType?.type || 'any'}, ${valueType?.type || 'any'}>`,
297
- isOptional: false,
298
- description,
299
- };
300
- }
301
- case 'ZodIntersection':
302
- return { type: 'intersection', isOptional: false, description };
303
- case 'ZodLiteral':
304
- return { type: JSON.stringify(field._def?.value), isOptional: false, description };
305
- default:
306
- return {
307
- type: typeName.replace('Zod', '').toLowerCase() || 'any',
308
- isOptional: false,
309
- description,
310
- };
311
- }
312
- }
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
- _buildSystemPrompt() {
323
- // 如果没变脏,返回缓存
324
- if (!this._systemPromptDirty && this._systemPromptCache !== null) {
325
- return this._systemPromptCache;
326
- }
327
-
328
- // 使用 builder 构建系统提示词
329
- this._systemPromptCache = this._systemPromptBuilder.build();
330
- this._systemPromptDirty = false;
331
- return this._systemPromptCache;
332
- }
333
-
334
- /**
335
- * 使 system prompt 缓存失效
336
- * @private
337
- */
338
- _invalidateSystemPromptCache() {
339
- this._systemPromptDirty = true;
340
- // 同时使 builder 中所有部分失效
341
- this._systemPromptBuilder.invalidateAll();
342
- }
343
-
344
- /**
345
- * 注册自定义系统提示词部分(供插件使用)
346
- * @param {string} name - 部分名称
347
- * @param {number} priority - 优先级
348
- * @param {Function} provider - 返回提示词内容的函数
349
- */
350
- registerPromptPart(name, priority, provider) {
351
- this._systemPromptBuilder.register(name, priority, provider);
352
- this._invalidateSystemPromptCache();
353
- return this;
354
- }
355
-
356
- /**
357
- * 注销系统提示词部分
358
- * @param {string} name - 部分名称
359
- */
360
- unregisterPromptPart(name) {
361
- this._systemPromptBuilder.unregister(name);
362
- this._invalidateSystemPromptCache();
363
- return this;
364
- }
365
-
366
- /**
367
- * 使特定系统提示词部分失效
368
- * @param {string} name - 部分名称
369
- */
370
- invalidatePromptPart(name) {
371
- this._systemPromptBuilder.invalidate(name);
372
- this._systemPromptDirty = true;
373
- return this;
374
- }
375
-
376
- /**
377
- * 刷新上下文
378
- */
379
- _refreshContext() {
380
- this.systemPrompt = this._buildSystemPrompt();
381
- if (this._chatHandler) {
382
- this._chatHandler.setSystemPrompt(this.systemPrompt);
383
- }
384
- }
385
-
386
- /**
387
- * 初始化聊天处理器
388
- * @private
389
- */
390
- _initChatHandler() {
391
- let aiClient = null;
392
- const aiPlugin = this.framework.pluginManager.get('ai');
393
- if (aiPlugin) {
394
- aiClient = aiPlugin.getAIClient();
395
- }
396
-
397
- this._chatHandler = new AgentChatHandler(this, {
398
- model: this.model,
399
- provider: this.provider,
400
- apiKey: this.apiKey,
401
- baseURL: this.baseURL,
402
- providerOptions: this.providerOptions,
403
- // 上下文压缩配置
404
- maxContextTokens: this.config.maxContextTokens,
405
- compressionThreshold: this.config.compressionThreshold,
406
- compressionMessageThreshold: this.config.compressionMessageThreshold,
407
- keepRecentMessages: this.config.keepRecentMessages,
408
- enableSmartCompress: this.config.enableSmartCompress,
409
- });
410
-
411
- if (aiClient) {
412
- this._chatHandler.setAIClient(aiClient);
413
- }
414
-
415
- // 转发事件
416
- this._chatHandler.on('message', (msg) => this.emit('message', msg));
417
- this._chatHandler.on('chunk', (chunk) => this.emit('chunk', chunk));
418
- this._chatHandler.on('tool-call', (tool) => this.emit('tool-call', tool));
419
- this._chatHandler.on('tool-result', (result) => this.emit('tool-result', result));
420
- this._chatHandler.on('error', (err) => this.emit('error', err));
421
-
422
- this._syncTools();
423
- }
424
-
425
- /**
426
- * 获取原始系统提示文本
427
- * @returns {string}
428
- */
429
- getOriginalPrompt() {
430
- return this._originalPrompt;
431
- }
432
-
433
- /**
434
- * 设置系统提示
435
- */
436
- setSystemPrompt(prompt) {
437
- this._originalPrompt = prompt;
438
- this.systemPrompt = this._buildSystemPrompt();
439
- if (this._chatHandler) {
440
- this._chatHandler.setSystemPrompt(this.systemPrompt);
441
- }
442
- return this;
443
- }
444
-
445
- /**
446
- * 注册工具到 Framework(统一入口)
447
- */
448
- registerTool(tool) {
449
- // 注册到 framework(统一管理)
450
- this.framework.registerTool(tool);
451
- // 注册到 chatHandler
452
- if (this._chatHandler) {
453
- this._chatHandler.registerTool(tool);
454
- }
455
- this._invalidateSystemPromptCache();
456
- this._refreshContext();
457
- return this;
458
- }
459
-
460
- /**
461
- * 获取已注册工具(从 framework 获取)
462
- */
463
- getTools() {
464
- return this.framework.getTools();
465
- }
466
-
467
- /**
468
- * 同步框架中的工具到 ChatHandler
469
- * @private
470
- */
471
- _syncTools() {
472
- // 从 framework 获取工具并注册到 chatHandler
473
- const tools = this.framework.getTools();
474
- for (const tool of tools) {
475
- // 直接注册到 chatHandler(registerTool 是幂等的)
476
- if (this._chatHandler) {
477
- this._chatHandler.registerTool(tool);
478
- }
479
- }
480
- }
481
-
482
- /**
483
- * 注册子Agent
484
- * @param {string} name - 子Agent名称
485
- * @param {Agent} agent - 子Agent实例
486
- * @param {string} role - 角色描述
487
- * @param {string} goal - 目标描述
488
- */
489
- registerSubAgent(name, agent, role, goal) {
490
- this._subAgents.set(name, { agent, role, goal });
491
- this._invalidateSystemPromptCache();
492
- this._refreshContext();
493
- return this;
494
- }
495
-
496
- /**
497
- * 注销子Agent
498
- */
499
- unregisterSubAgent(name) {
500
- this._subAgents.delete(name);
501
- this._invalidateSystemPromptCache();
502
- this._refreshContext();
503
- return this;
504
- }
505
-
506
- /**
507
- * 获取所有子Agent
508
- */
509
- getSubAgents() {
510
- return this._subAgents;
511
- }
512
-
513
- /**
514
- * 发送消息
515
- */
516
- async chat(message, options = {}) {
517
- if (this._status === 'error') {
518
- this._status = 'idle';
519
- }
520
-
521
- this._status = 'busy';
522
- this.emit('status', { status: 'busy' });
523
-
524
- try {
525
- // 使用 NotificationManager 增强消息
526
- const enhancedMessage = this._notificationManager.enhanceMessage(message);
527
-
528
- // 子agent跳过工具同步,使用createSubAgent时已配置的工具
529
- if (!this._skipSyncTools) {
530
- this._syncTools();
531
- }
532
-
533
- // 通过 handler 的 enqueue 处理(自动排队)
534
- const result = await this._chatHandler.chat(enhancedMessage, options);
535
-
536
- this._status = 'idle';
537
- this.emit('status', { status: 'idle' });
538
-
539
- return result;
540
- } catch (err) {
541
- this._status = 'error';
542
- logger.error('Agent', `chat 方法执行失败: ${err.message}`, { stack: err.stack });
543
- this.emit('status', { status: 'error', error: err.message });
544
- throw err;
545
- }
546
- }
547
-
548
- /**
549
- * 推送消息(自动继承当前 sessionId 上下文,自动排队)
550
- * 工具中调用此方法,自动带上当前执行上下文的 sessionId
551
- * 如果 agent 忙碌,消息会进入队列等待
552
- * @param {string|Object} message - 消息
553
- * @param {Object} options - 选项 { maxSteps }
554
- * @returns {Promise<{success: boolean, message: string, stepCount: number}>}
555
- */
556
- async pushMessage(message, options = {}) {
557
- // 自动从执行上下文获取 sessionId
558
- const ctx = this.framework.getExecutionContext();
559
- if (ctx?.sessionId && !options.sessionId) {
560
- options.sessionId = ctx.sessionId;
561
- }
562
-
563
- // 直接调用 chat,由 handler 的 enqueue 处理排队
564
- return this.chat(message, options);
565
- }
566
-
567
- /**
568
- * 发送消息(流式)
569
- */
570
- async *chatStream(message, options = {}) {
571
- if (this._status === 'busy') {
572
- throw new Error('Agent is busy');
573
- }
574
-
575
- // 允许从 error 状态重试
576
- if (this._status === 'error') {
577
- this._status = 'idle';
578
- }
579
-
580
- this._status = 'busy';
581
- this.emit('status', { status: 'busy' });
582
-
583
- try {
584
- // 使用 NotificationManager 增强消息
585
- const enhancedMessage = this._notificationManager.enhanceMessage(message);
586
-
587
- // 子agent跳过工具同步,使用createSubAgent时已配置的工具
588
- if (!this._skipSyncTools) {
589
- this._syncTools();
590
- }
591
-
592
- yield* this._chatHandler.chatStream(enhancedMessage, options);
593
- this._status = 'idle';
594
- this.emit('status', { status: 'idle' });
595
- } catch (err) {
596
- this._status = 'error';
597
- logger.error('Agent', `chatStream 方法执行失败: ${err.message}`, { stack: err.stack });
598
- this.emit('status', { status: 'error', error: err.message });
599
-
600
- throw err;
601
- }
602
- }
603
-
604
- createSessionScope(sessionid) {
605
- return this._chatHandler.createSessionScope(sessionid);
606
- }
607
-
608
- /**
609
- * 发送消息(带队列)
610
- */
611
- async sendMessage(message, options = {}) {
612
- return this._chatHandler.sendMessage(message, options);
613
- }
614
-
615
- /**
616
- * 流式发送消息(带队列,支持实时yield)
617
- */
618
- async *sendMessageStream(message, options = {}) {
619
- yield* this._chatHandler.sendMessageStream(message, options);
620
- }
621
-
622
- /**
623
- * 批量发送消息
624
- */
625
- async sendBatch(messages, options = {}) {
626
- return this._chatHandler.sendBatch(messages, options);
627
- }
628
-
629
- /**
630
- * 取消会话的所有请求
631
- */
632
- cancelSession(sessionId) {
633
- return this._chatHandler.cancelSession(sessionId);
634
- }
635
-
636
- /**
637
- * 设置元数据
638
- */
639
- setMetadata(keyOrObj, value) {
640
- if (typeof keyOrObj === 'string') {
641
- this._metadata.set(keyOrObj, value);
642
- } else if (keyOrObj && typeof keyOrObj === 'object') {
643
- for (const [key, val] of Object.entries(keyOrObj)) {
644
- this._metadata.set(key, val);
645
- }
646
- }
647
- this._invalidateSystemPromptCache();
648
- this._refreshContext();
649
- return this;
650
- }
651
-
652
- /**
653
- * 获取元数据
654
- */
655
- getMetadata(key) {
656
- return this._metadata.get(key);
657
- }
658
-
659
- /**
660
- * 删除元数据
661
- */
662
- deleteMetadata(key) {
663
- this._metadata.delete(key);
664
- this._refreshContext();
665
- return this;
666
- }
667
-
668
- /**
669
- * 清空元数据
670
- */
671
- clearMetadata() {
672
- this._metadata.clear();
673
- this._refreshContext();
674
- return this;
675
- }
676
-
677
- /**
678
- * 清空对话历史(所有存储层)
679
- * @param {string} sessionId
680
- */
681
- clearContext(sessionId) {
682
- if (!sessionId || !this._chatHandler) return;
683
-
684
- this._chatHandler._chatSession?.clearSessionMessages(sessionId, true);
685
-
686
- const sessionCtx = this.framework?.getSessionContext(sessionId);
687
- if (sessionCtx) {
688
- sessionCtx.clearMessages();
689
- if (sessionCtx.compressionState) sessionCtx.compressionState.count = 0;
690
- if (sessionCtx.metadata) sessionCtx.metadata.compressionCount = 0;
691
- }
692
-
693
- // 持久化 CLEAR 标记到 SessionManager
694
- const sessionManager = this.framework?._sessionContexts?.get(sessionId);
695
- if (sessionManager) {
696
- const { generateEntryId, EntryTypes } = require('./session-entry');
697
- sessionManager._appendEntry({
698
- id: generateEntryId(sessionManager.byId),
699
- type: EntryTypes.SESSION_INFO,
700
- info: 'context_cleared',
701
- timestamp: Date.now(),
702
- });
703
- }
704
- }
705
-
706
- /**
707
- * 压缩上下文(委托给 AgentChatHandler.ContextCompressor)
708
- * @param {string} sessionId
709
- * @returns {Promise<{before: number, after: number}>}
710
- */
711
- async compressContext(sessionId) {
712
- if (!sessionId || !this._chatHandler) {
713
- throw new Error('AgentChatHandler not available');
714
- }
715
-
716
- const chatHandler = this._chatHandler;
717
- const messageStore = chatHandler._chatSession?.getSessionMessageStore(sessionId);
718
- if (!messageStore) throw new Error('MessageStore not available');
719
-
720
- messageStore.historyLoaded = false;
721
- chatHandler._chatSession?.loadHistory(sessionId);
722
-
723
- let messages = messageStore.messages;
724
- const sessionCtx = this.framework?.getSessionContext(sessionId);
725
- if (!messages?.length && sessionCtx) {
726
- messages = sessionCtx.getMessages();
727
- messageStore.messages = messages;
728
- }
729
-
730
- if (!messages?.length) {
731
- throw new Error('No messages to compress');
732
- }
733
-
734
- if (!chatHandler._contextCompressor) {
735
- throw new Error('ContextCompressor not available');
736
- }
737
-
738
- const before = messages.length;
739
- await chatHandler._contextCompressor.compress(sessionId, messages, messageStore);
740
- const after = messages.length;
741
-
742
- if (sessionCtx) sessionCtx.replaceMessages(messages);
743
-
744
- // 持久化 COMPACTION 条目到 SessionManager
745
- const sessionManager = this.framework?._sessionContexts?.get(sessionId);
746
- if (sessionManager) {
747
- const { generateEntryId, EntryTypes } = require('./session-entry');
748
- const compactionEntry = {
749
- id: generateEntryId(sessionManager.byId),
750
- type: EntryTypes.COMPACTION,
751
- summary: messages.find(m => m.role === 'assistant' && m.content?.startsWith('['))?.content || '',
752
- firstKeptEntryId: null,
753
- tokensBefore: before,
754
- timestamp: Date.now(),
755
- };
756
- sessionManager._appendEntry(compactionEntry);
757
- }
758
-
759
- return { before, after, keepRecent: chatHandler._contextCompressor._keepRecentMessages };
760
- }
761
-
762
- /**
763
- * 获取状态
764
- */
765
- getStatus() {
766
- return this._status;
767
- }
768
-
769
- /**
770
- * 获取Agent ID
771
- * @returns {string} Agent名称
772
- */
773
- getCurrentAgentId() {
774
- return this.name;
775
- }
776
-
777
- /**
778
- * 重置状态(从卡住状态恢复)
779
- */
780
- resetStatus() {
781
- this._status = 'idle';
782
- this.emit('status', { status: 'idle' });
783
- return this;
784
- }
785
-
786
- /**
787
- * 销毁 Agent
788
- */
789
- destroy() {
790
- // 销毁所有子Agent
791
- for (const [name, { agent }] of this._subAgents) {
792
- if (typeof agent.destroy === 'function') {
793
- agent.destroy();
794
- }
795
- }
796
- this._subAgents.clear();
797
-
798
- if (this._chatHandler) {
799
- this._chatHandler.destroy();
800
- }
801
- this._tools.clear();
802
- this.removeAllListeners();
803
- this.emit('destroyed');
804
- logger.info('Agent', `Agent "${this.name}" 已销毁`);
805
- }
806
- }
807
-
808
- module.exports = { Agent };