foliko 1.0.74 → 1.0.76

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 (238) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +29 -0
  39. package/.agent/data/plugins-state.json +255 -0
  40. package/.agent/mcp_config.json +4 -0
  41. package/.agent/mcp_config_updated.json +12 -0
  42. package/.agent/plugins.json +5 -0
  43. package/.agent/rules/GEMINI.md +273 -0
  44. package/.agent/rules/allow-rule.md +77 -0
  45. package/.agent/rules/log-rule.md +83 -0
  46. package/.agent/rules/security-rule.md +93 -0
  47. package/.agent/scripts/auto_preview.py +148 -0
  48. package/.agent/scripts/checklist.py +217 -0
  49. package/.agent/scripts/session_manager.py +120 -0
  50. package/.agent/scripts/verify_all.py +327 -0
  51. package/.agent/skills/api-patterns/SKILL.md +81 -0
  52. package/.agent/skills/api-patterns/api-style.md +42 -0
  53. package/.agent/skills/api-patterns/auth.md +24 -0
  54. package/.agent/skills/api-patterns/documentation.md +26 -0
  55. package/.agent/skills/api-patterns/graphql.md +41 -0
  56. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  57. package/.agent/skills/api-patterns/response.md +37 -0
  58. package/.agent/skills/api-patterns/rest.md +40 -0
  59. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  60. package/.agent/skills/api-patterns/security-testing.md +122 -0
  61. package/.agent/skills/api-patterns/trpc.md +41 -0
  62. package/.agent/skills/api-patterns/versioning.md +22 -0
  63. package/.agent/skills/app-builder/SKILL.md +75 -0
  64. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  65. package/.agent/skills/app-builder/feature-building.md +53 -0
  66. package/.agent/skills/app-builder/project-detection.md +34 -0
  67. package/.agent/skills/app-builder/scaffolding.md +118 -0
  68. package/.agent/skills/app-builder/tech-stack.md +40 -0
  69. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  70. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  71. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  72. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  73. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  74. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  75. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  76. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  77. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  78. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  79. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  80. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  81. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  82. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  83. package/.agent/skills/architecture/SKILL.md +55 -0
  84. package/.agent/skills/architecture/context-discovery.md +43 -0
  85. package/.agent/skills/architecture/examples.md +94 -0
  86. package/.agent/skills/architecture/pattern-selection.md +68 -0
  87. package/.agent/skills/architecture/patterns-reference.md +50 -0
  88. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  89. package/.agent/skills/clean-code/SKILL.md +201 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/frontend-design/SKILL.md +418 -0
  92. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  93. package/.agent/skills/frontend-design/color-system.md +311 -0
  94. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  95. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  96. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  97. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  98. package/.agent/skills/frontend-design/typography-system.md +345 -0
  99. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  100. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  101. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  102. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  103. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  104. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  105. package/.agent/workflows/brainstorm.md +113 -0
  106. package/.agent/workflows/create.md +59 -0
  107. package/.agent/workflows/debug.md +103 -0
  108. package/.agent/workflows/deploy.md +176 -0
  109. package/.agent/workflows/enhance.md +63 -0
  110. package/.agent/workflows/orchestrate.md +237 -0
  111. package/.agent/workflows/plan.md +89 -0
  112. package/.agent/workflows/preview.md +81 -0
  113. package/.agent/workflows/simple-test.md +42 -0
  114. package/.agent/workflows/status.md +86 -0
  115. package/.agent/workflows/structured-orchestrate.md +180 -0
  116. package/.agent/workflows/test.md +144 -0
  117. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  118. package/.claude/settings.local.json +11 -1
  119. package/.editorconfig +56 -0
  120. package/.husky/pre-commit +4 -0
  121. package/.lintstagedrc +7 -0
  122. package/.prettierignore +29 -0
  123. package/.prettierrc +11 -0
  124. package/CLAUDE.md +2 -0
  125. package/README.md +64 -55
  126. package/SPEC.md +102 -61
  127. package/cli/bin/foliko.js +11 -11
  128. package/cli/src/commands/chat.js +143 -141
  129. package/cli/src/commands/list.js +93 -90
  130. package/cli/src/index.js +75 -75
  131. package/cli/src/ui/chat-ui.js +201 -199
  132. package/cli/src/utils/ansi.js +40 -40
  133. package/cli/src/utils/markdown.js +292 -296
  134. package/docker-compose.yml +1 -1
  135. package/docs/ai-sdk-optimization.md +655 -643
  136. package/docs/features.md +80 -80
  137. package/docs/quick-reference.md +49 -46
  138. package/docs/user-manual.md +411 -380
  139. package/examples/ambient-example.js +194 -196
  140. package/examples/basic.js +50 -45
  141. package/examples/bootstrap.js +121 -112
  142. package/examples/mcp-example.js +19 -16
  143. package/examples/skill-example.js +20 -20
  144. package/examples/test-chat.js +137 -135
  145. package/examples/test-mcp.js +85 -79
  146. package/examples/test-reload.js +59 -61
  147. package/examples/test-telegram.js +50 -50
  148. package/examples/test-tg-bot.js +45 -42
  149. package/examples/test-tg-simple.js +47 -46
  150. package/examples/test-tg.js +62 -62
  151. package/examples/test-think.js +43 -37
  152. package/examples/test-web-plugin.js +103 -98
  153. package/examples/test-weixin-feishu.js +103 -100
  154. package/examples/workflow.js +158 -158
  155. package/package.json +37 -3
  156. package/plugins/ai-plugin.js +102 -100
  157. package/plugins/ambient-agent/EventWatcher.js +113 -0
  158. package/plugins/ambient-agent/ExplorerLoop.js +640 -0
  159. package/plugins/ambient-agent/GoalManager.js +197 -0
  160. package/plugins/ambient-agent/Reflector.js +95 -0
  161. package/plugins/ambient-agent/StateStore.js +90 -0
  162. package/plugins/ambient-agent/constants.js +101 -0
  163. package/plugins/ambient-agent/index.js +579 -0
  164. package/plugins/audit-plugin.js +187 -187
  165. package/plugins/default-plugins.js +662 -649
  166. package/plugins/email/constants.js +64 -0
  167. package/plugins/email/handlers.js +461 -0
  168. package/plugins/email/index.js +278 -0
  169. package/plugins/email/monitor.js +269 -0
  170. package/plugins/email/parser.js +138 -0
  171. package/plugins/email/reply.js +151 -0
  172. package/plugins/email/utils.js +124 -0
  173. package/plugins/feishu-plugin.js +481 -477
  174. package/plugins/file-system-plugin.js +826 -476
  175. package/plugins/install-plugin.js +199 -197
  176. package/plugins/python-executor-plugin.js +367 -365
  177. package/plugins/python-plugin-loader.js +481 -479
  178. package/plugins/rules-plugin.js +294 -292
  179. package/plugins/scheduler-plugin.js +691 -689
  180. package/plugins/session-plugin.js +369 -367
  181. package/plugins/shell-executor-plugin.js +197 -197
  182. package/plugins/storage-plugin.js +240 -238
  183. package/plugins/subagent-plugin.js +845 -785
  184. package/plugins/telegram-plugin.js +482 -475
  185. package/plugins/think-plugin.js +345 -343
  186. package/plugins/tools-plugin.js +196 -194
  187. package/plugins/web-plugin.js +606 -604
  188. package/plugins/weixin-plugin.js +545 -538
  189. package/reports/system-health-report-20260401.md +79 -0
  190. package/skills/ambient-agent/SKILL.md +49 -39
  191. package/skills/foliko-dev/AGENTS.md +64 -61
  192. package/skills/foliko-dev/SKILL.md +125 -119
  193. package/skills/mcp-usage/SKILL.md +19 -17
  194. package/skills/python-plugin-dev/SKILL.md +16 -15
  195. package/skills/skill-guide/SKILL.md +12 -12
  196. package/skills/subagent-guide/SKILL.md +237 -0
  197. package/skills/workflow-guide/SKILL.md +90 -45
  198. package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
  199. package/skills/workflow-troubleshooting/SKILL.md +156 -79
  200. package/src/capabilities/index.js +11 -11
  201. package/src/capabilities/skill-manager.js +609 -595
  202. package/src/capabilities/workflow-engine.js +1109 -1195
  203. package/src/core/agent-chat.js +882 -735
  204. package/src/core/agent.js +892 -688
  205. package/src/core/framework.js +465 -431
  206. package/src/core/index.js +19 -19
  207. package/src/core/plugin-base.js +219 -219
  208. package/src/core/plugin-manager.js +863 -767
  209. package/src/core/provider.js +114 -111
  210. package/src/core/sub-agent-config.js +264 -0
  211. package/src/core/system-prompt-builder.js +120 -0
  212. package/src/core/tool-registry.js +517 -134
  213. package/src/core/tool-router.js +297 -216
  214. package/src/executors/executor-base.js +12 -12
  215. package/src/executors/mcp-executor.js +741 -729
  216. package/src/index.js +25 -37
  217. package/src/utils/circuit-breaker.js +301 -0
  218. package/src/utils/error-boundary.js +363 -0
  219. package/src/utils/error.js +374 -0
  220. package/src/utils/event-emitter.js +97 -97
  221. package/src/utils/id.js +133 -0
  222. package/src/utils/index.js +217 -3
  223. package/src/utils/logger.js +181 -0
  224. package/src/utils/plugin-helpers.js +90 -0
  225. package/src/utils/retry.js +122 -0
  226. package/src/utils/sandbox.js +292 -0
  227. package/test/tool-registry-validation.test.js +218 -0
  228. package/test_report.md +70 -0
  229. package/website/docs/api.html +169 -107
  230. package/website/docs/configuration.html +296 -144
  231. package/website/docs/plugin-development.html +154 -85
  232. package/website/docs/project-structure.html +110 -109
  233. package/website/docs/skill-development.html +117 -61
  234. package/website/index.html +209 -205
  235. package/website/script.js +136 -133
  236. package/website/styles.css +1 -1
  237. package/plugins/ambient-agent-plugin.js +0 -1565
  238. package/plugins/email.js +0 -1142
package/src/core/agent.js CHANGED
@@ -1,688 +1,892 @@
1
- /**
2
- * Agent 类
3
- * 负责对话和推理
4
- */
5
-
6
- const { EventEmitter } = require('../utils/event-emitter')
7
- const { AgentChatHandler } = require('./agent-chat')
8
- const os = require('os')
9
-
10
- class Agent extends EventEmitter {
11
- /**
12
- * @param {Framework} framework - 框架实例
13
- * @param {Object} config - 配置
14
- * @param {string} [config.name] - Agent 名称
15
- * @param {string} [config.systemPrompt] - 系统提示
16
- * @param {string} [config.sharedPrompt] - 共享提示模板,支持 {{VAR}} 占位符
17
- * @param {Object} [config.metadata] - 元数据,注入到 sharedPrompt
18
- * @param {boolean} [config.enableToolRouting=true] - 是否启用工具路由
19
- */
20
- constructor(framework, config = {}) {
21
- super()
22
-
23
- this.framework = framework
24
- this.config = config
25
-
26
- this.name = config.name || 'Agent'
27
- this.model = config.model || 'deepseek-chat'
28
- this.apiKey = config.apiKey
29
- this.baseURL = config.baseURL
30
- this.provider = config.provider || 'deepseek'
31
- this.providerOptions = config.providerOptions || {}
32
- this.providerOptions.maxOutputTokens = 8192
33
- this.providerOptions.temperature = 0.3 // 降低 temperature 减少生成错误 JSON 的概率
34
- // 原始 system prompt
35
- this._originalPrompt = config.systemPrompt || '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。'
36
-
37
- // 共享提示模板
38
- this._sharedPrompt = config.sharedPrompt || ''
39
-
40
- // 元数据
41
- const metadata = config.metadata || {}
42
- this._metadata = new Map(Object.entries(metadata))
43
-
44
- this._chatHandler = null
45
- this._tools = new Map()
46
- this._status = 'idle'
47
-
48
- // 子Agent管理
49
- this._subAgents = new Map()
50
-
51
- // 消息队列(用于 pushMessage)
52
- this._messageQueue = []
53
- this._isProcessingQueue = false
54
-
55
- // 处理后的 system prompt (带上下文)
56
- this.systemPrompt = this._buildSystemPrompt()
57
-
58
- // 初始化聊天处理器
59
- this._initChatHandler()
60
- }
61
-
62
- /**
63
- * 获取元数据值
64
- */
65
- _getMetadataValue(key) {
66
- // 优先从 metadata 获取
67
- if (this._metadata.has(key)) {
68
- return this._metadata.get(key)
69
- }
70
-
71
- // 内置变量
72
- switch (key) {
73
- case 'WORK_DIR':
74
- case 'CWD':
75
- return process.cwd()
76
- case 'HOME_DIR':
77
- return os.homedir()
78
- case 'HOST_NAME':
79
- return os.hostname()
80
- case 'PLATFORM':
81
- return process.platform
82
- case 'TIME':
83
- return new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
84
- case 'DATE':
85
- return new Date().toISOString().split('T')[0]
86
- default:
87
- return `{{${key}}}`
88
- }
89
- }
90
-
91
- /**
92
- * 替换 sharedPrompt 中的占位符
93
- */
94
- _replacePlaceholders(template) {
95
- return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
96
- return this._getMetadataValue(key)
97
- })
98
- }
99
-
100
- /**
101
- * 构建工具描述
102
- */
103
- _buildToolsDescription() {
104
- if (this._tools.size === 0) {
105
- return ''
106
- }
107
-
108
- let desc = '【可用工具】\n'
109
- for (const [name, tool] of this._tools) {
110
- // 跳过没有描述的工具(对LLM无帮助)
111
- if (!tool.description) continue
112
- desc += `- ${name}: ${tool.description}\n`
113
- }
114
- return desc.trim()
115
- }
116
-
117
- /**
118
- * 构建技能描述
119
- */
120
- _buildSkillsDescription() {
121
- const skillManager = this.framework.pluginManager.get('skill-manager')
122
- if (!skillManager) {
123
- return ''
124
- }
125
-
126
- const skills = skillManager.getAllSkills()
127
- if (!skills || skills.length === 0) {
128
- return ''
129
- }
130
-
131
- let desc = '【可用技能】\n'
132
- for (const skill of skills) {
133
- const name = skill.metadata?.name || skill.name || 'unknown'
134
- const descText = skill.metadata?.description || ''
135
- desc += `- ${name}: ${descText}\n`
136
- }
137
- desc += '\n重要:当需要开发插件、执行专业任务时,必须先使用 loadSkill 工具加载对应技能,获取专业指导。'
138
- return desc.trim()
139
- }
140
-
141
- /**
142
- * 构建系统能力描述
143
- */
144
- _buildCapabilitiesDescription() {
145
- const plugins = this.framework.pluginManager.getAll()
146
- if (!plugins || plugins.length === 0) {
147
- return ''
148
- }
149
-
150
- // 过滤出有描述的关键插件(排除内部插件)
151
- const keyPlugins = plugins.filter(p => {
152
- const name = p.name
153
- // 排除默认配置插件和内部插件
154
- return name !== 'defaults' && name !== 'agent'
155
- })
156
-
157
- if (keyPlugins.length === 0) {
158
- return ''
159
- }
160
-
161
- let desc = '【系统能力】\n'
162
- for (const plugin of keyPlugins) {
163
- const name = plugin.instance?.name || plugin.name || 'unknown'
164
- const description = plugin.instance?.description || '无描述'
165
- desc += `- ${name}: ${description}\n`
166
- }
167
-
168
- return desc.trim()
169
- }
170
-
171
- /**
172
- * 构建子Agent描述
173
- */
174
- _buildSubAgentsDescription() {
175
- if (this._subAgents.size === 0) {
176
- return ''
177
- }
178
-
179
- let desc = '【子 Agent 分配规则 - 必须遵守】\n'
180
- desc += '1. 每个子Agent有固定的专业领域,必须委托给对应的专家:\n'
181
- for (const [name, { role, goal }] of this._subAgents) {
182
- desc += ` - ${name}: ${role || goal || '子代理'}\n`
183
- }
184
- desc += '2. 你需要对任务进行拆分,传递给对应的子Agent执行。\n'
185
- desc += '3. 多个不同类型的任务必须分别委托给不同的子Agent,每个子Agent只处理自己专业领域的任务。\n'
186
- desc += '\n【可委托的子 Agent】\n'
187
- for (const [name, { role, goal }] of this._subAgents) {
188
- desc += ` - ${name}: ${role || goal || '子代理'}\n`
189
- }
190
- desc += '\n使用 subagent_call 工具并指定 agentName 来委托任务给相应子Agent。'
191
-
192
- return desc.trim()
193
- }
194
-
195
- /**
196
- * 构建系统提示(带上下文)
197
- */
198
- _buildSystemPrompt() {
199
- const parts = []
200
-
201
- // 1. 原始 system prompt
202
- parts.push(this._originalPrompt)
203
-
204
- // 2. 共享提示模板(带占位符替换)
205
- if (this._sharedPrompt) {
206
- const replaced = this._replacePlaceholders(this._sharedPrompt)
207
- parts.push(replaced)
208
- }
209
-
210
- // 3. 元数据
211
- if (this._metadata.size > 0) {
212
- const metaParts = ['【元数据】']
213
- for (const [key, value] of this._metadata) {
214
- if (typeof value === 'object') {
215
- metaParts.push(`- ${key}: ${JSON.stringify(value)}`)
216
- } else {
217
- metaParts.push(`- ${key}: ${value}`)
218
- }
219
- }
220
- parts.push(metaParts.join('\n'))
221
- }
222
-
223
- // 4. 工具列表
224
- const toolsDesc = this._buildToolsDescription()
225
- if (toolsDesc) {
226
- parts.push(toolsDesc)
227
- }
228
-
229
- // 5. 技能列表
230
- const skillsDesc = this._buildSkillsDescription()
231
- if (skillsDesc) {
232
- parts.push(skillsDesc)
233
- }
234
-
235
- // 6. 子Agent列表
236
- const subAgentsDesc = this._buildSubAgentsDescription()
237
- if (subAgentsDesc) {
238
- parts.push(subAgentsDesc)
239
- }
240
-
241
- // 7. 系统能力
242
- const capabilitiesDesc = this._buildCapabilitiesDescription()
243
- if (capabilitiesDesc) {
244
- parts.push(capabilitiesDesc)
245
- }
246
-
247
- // 8. 工具调用核心规则(统一追加到所有 Agent)
248
- const toolCoreRules = this._getToolCoreRules()
249
- if (toolCoreRules) {
250
- parts.push(toolCoreRules)
251
- }
252
-
253
- return parts.join('\n\n')
254
- }
255
-
256
- /**
257
- * 获取工具调用核心规则
258
- * @private
259
- */
260
- _getToolCoreRules() {
261
- return `【工具调用核心规则】
262
- 1. **必须先调用工具再回复**:当问题需要信息、操作或计算时,必须调用工具获取真实结果后才能回答。禁止在未调用工具的情况下直接给出答案。
263
- 2. **禁止编造数据**:不许捏造用户、订单、任务、文件、内容等任何数据。所有数据必须通过工具获取。
264
- 3. **工具优先**:可用工具列表会提供,格式为 toolName(toolArgs)。不确定用哪个工具时,优先调用可能相关的工具。
265
- 4. **结果导向**:调用工具后,基于返回结果回答,不要重复工具的内部实现细节。
266
- 5. **多步骤任务**:复杂任务拆解为多个工具调用,逐步完成,每步基于结果决定下一步。
267
- 6. **子Agent委托**:当任务匹配子Agent专业领域时,使用 subagent_call 工具委托给对应子Agent处理。
268
-
269
- 【响应规范】
270
- - 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
271
- - 如果工具返回错误,说明错误原因并给出解决建议
272
- - 如果信息不足,先调用工具获取必要信息,不要假设或猜测
273
-
274
- 【禁止事项】
275
- - 不调用工具就直接回答
276
- - 编造不存在的数据、文件、订单、用户等信息
277
- - 回复含糊不清,让用户无法确定答案是否正确`
278
- }
279
-
280
- /**
281
- * 刷新上下文
282
- */
283
- _refreshContext() {
284
- this.systemPrompt = this._buildSystemPrompt()
285
- if (this._chatHandler) {
286
- this._chatHandler.setSystemPrompt(this.systemPrompt)
287
- }
288
- }
289
-
290
- /**
291
- * 初始化聊天处理器
292
- * @private
293
- */
294
- _initChatHandler() {
295
- let aiClient = null
296
- const aiPlugin = this.framework.pluginManager.get('ai')
297
- if (aiPlugin) {
298
- aiClient = aiPlugin.getAIClient()
299
- }
300
-
301
- this._chatHandler = new AgentChatHandler(this, {
302
- model: this.model,
303
- provider: this.provider,
304
- apiKey: this.apiKey,
305
- baseURL: this.baseURL,
306
- providerOptions: this.providerOptions,
307
- // 上下文压缩配置
308
- maxContextTokens: this.config.maxContextTokens,
309
- compressionThreshold: this.config.compressionThreshold,
310
- keepRecentMessages: this.config.keepRecentMessages,
311
- enableSmartCompress: this.config.enableSmartCompress
312
- })
313
-
314
- if (aiClient) {
315
- this._chatHandler.setAIClient(aiClient)
316
- }
317
-
318
- // 转发事件
319
- this._chatHandler.on('message', (msg) => this.emit('message', msg))
320
- this._chatHandler.on('chunk', (chunk) => this.emit('chunk', chunk))
321
- this._chatHandler.on('tool-call', (tool) => this.emit('tool-call', tool))
322
- this._chatHandler.on('tool-result', (result) => this.emit('tool-result', result))
323
- this._chatHandler.on('error', (err) => this.emit('error', err))
324
-
325
- this._syncTools()
326
- }
327
-
328
- /**
329
- * 设置系统提示
330
- */
331
- setSystemPrompt(prompt) {
332
- this._originalPrompt = prompt
333
- this.systemPrompt = this._buildSystemPrompt()
334
- if (this._chatHandler) {
335
- this._chatHandler.setSystemPrompt(this.systemPrompt)
336
- }
337
- return this
338
- }
339
-
340
- /**
341
- * 注册工具到 Agent
342
- */
343
- registerTool(tool) {
344
- this._tools.set(tool.name, tool)
345
- if (this._chatHandler) {
346
- this._chatHandler.registerTool(tool)
347
- }
348
- this._refreshContext()
349
- return this
350
- }
351
-
352
- /**
353
- * 获取已注册工具
354
- */
355
- getTools() {
356
- return Array.from(this._tools.values())
357
- }
358
-
359
- /**
360
- * 同步框架中的工具到 Agent
361
- * @private
362
- */
363
- _syncTools() {
364
- if (this.framework.toolRegistry.size() > 0) {
365
- for (const tool of this.framework.getTools()) {
366
- if (!this._tools.has(tool.name)) {
367
- this.registerTool(tool)
368
- }
369
- }
370
- }
371
- }
372
-
373
- /**
374
- * 注册子Agent
375
- * @param {string} name - 子Agent名称
376
- * @param {Agent} agent - 子Agent实例
377
- * @param {string} role - 角色描述
378
- * @param {string} goal - 目标描述
379
- */
380
- registerSubAgent(name, agent, role, goal) {
381
- this._subAgents.set(name, { agent, role, goal })
382
- this._refreshContext()
383
- return this
384
- }
385
-
386
- /**
387
- * 注销子Agent
388
- */
389
- unregisterSubAgent(name) {
390
- this._subAgents.delete(name)
391
- this._refreshContext()
392
- return this
393
- }
394
-
395
- /**
396
- * 获取所有子Agent
397
- */
398
- getSubAgents() {
399
- return this._subAgents
400
- }
401
-
402
- /**
403
- * 获取待处理的调度通知并清除(下次不再重复显示)
404
- */
405
- _getAndClearSchedulerNotifications() {
406
- try {
407
- const scheduler = this.framework.pluginManager.get('scheduler')
408
- if (scheduler && scheduler.instance && scheduler.instance.getPendingNotifications) {
409
- const results = scheduler.instance.getPendingNotifications()
410
- if (results.length > 0) {
411
- const notifications = results.slice(-5).reverse() // 最多5条,最新的在前
412
- // 清除已发送的通知
413
- if (scheduler.instance.clearDeliveredNotifications) {
414
- scheduler.instance.clearDeliveredNotifications(notifications.length)
415
- }
416
- return notifications
417
- }
418
- }
419
- } catch (err) {
420
- // 忽略错误,避免影响主流程
421
- }
422
- return []
423
- }
424
-
425
- /**
426
- * 获取待处理的思考结果并清除
427
- */
428
- _getAndClearThinkNotifications() {
429
- try {
430
- const think = this.framework.pluginManager.get('think')
431
- if (think && think.instance && think.instance.getPendingThoughts) {
432
- const thoughts = think.instance.getPendingThoughts()
433
- if (thoughts.length > 0) {
434
- return thoughts.slice(-5).reverse() // 最多5条,最新的在前
435
- }
436
- }
437
- } catch (err) {
438
- // 忽略错误,避免影响主流程
439
- }
440
- return []
441
- }
442
-
443
- /**
444
- * 获取所有待处理的系统通知(调度 + 思考)
445
- */
446
- _getAllPendingNotifications() {
447
- const notifications = []
448
-
449
- // 调度通知
450
- const schedulerNotifs = this._getAndClearSchedulerNotifications()
451
- for (const n of schedulerNotifs) {
452
- notifications.push(`【定时任务通知】\n任务: ${n.taskName || n.taskId}\n执行时间: ${n.executedAt}\n结果: ${n.result || n.action || '执行完成'}`)
453
- }
454
-
455
- // 思考通知
456
- const thinkNotifs = this._getAndClearThinkNotifications()
457
- for (const t of thinkNotifs) {
458
- notifications.push(`【主动思考】\n模式: ${t.mode}\n主题: ${t.topic}\n结果: ${t.result || '思考完成'}`)
459
- }
460
-
461
- return notifications
462
- }
463
-
464
- /**
465
- * 发送消息
466
- */
467
- async chat(message, options = {}) {
468
- if (this._status === 'busy') {
469
- throw new Error('Agent is busy')
470
- }
471
-
472
- if (this._status === 'error') {
473
- this._status = 'idle'
474
- }
475
-
476
- this._status = 'busy'
477
- this.emit('status', { status: 'busy' })
478
-
479
- try {
480
- // 检查是否有待处理的系统通知(调度 + 思考)
481
- const notifications = this._getAllPendingNotifications()
482
- let enhancedMessage = message
483
- if (notifications.length > 0) {
484
- enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`
485
- }
486
-
487
- this._syncTools()
488
-
489
- const result = await this._chatHandler.chat(enhancedMessage, options)
490
- this._status = 'idle'
491
- this.emit('status', { status: 'idle' })
492
-
493
- // 处理队列中的下一条消息
494
- setImmediate(() => this._processQueue())
495
-
496
- return result
497
- } catch (err) {
498
- this._status = 'error'
499
- this.emit('status', { status: 'error', error: err.message })
500
-
501
- // 发生错误时也要处理队列
502
- setImmediate(() => this._processQueue())
503
-
504
- throw err
505
- }
506
- }
507
-
508
- /**
509
- * 推送消息(自动继承当前 sessionId 上下文,自动排队)
510
- * 工具中调用此方法,自动带上当前执行上下文的 sessionId
511
- * 如果 agent 忙碌,消息会进入队列等待
512
- * @param {string|Object} message - 消息
513
- * @param {Object} options - 选项 { maxSteps }
514
- * @returns {Promise<{success: boolean, message: string, stepCount: number}>}
515
- */
516
- async pushMessage(message, options = {}) {
517
- // 自动从执行上下文获取 sessionId
518
- const ctx = this.framework.getExecutionContext()
519
- if (ctx?.sessionId && !options.sessionId) {
520
- options.sessionId = ctx.sessionId
521
- }
522
-
523
- // 如果忙碌,进入队列等待
524
- if (this._status === 'busy') {
525
- const queuedItem = { message, options, resolve: null, reject: null }
526
- const promise = new Promise((resolve, reject) => {
527
- queuedItem.resolve = resolve
528
- queuedItem.reject = reject
529
- })
530
- this._messageQueue.push(queuedItem)
531
- console.log('[Agent] busy, message queued')
532
- return promise
533
- }
534
-
535
- // 空闲则直接处理
536
- return this.chat(message, options)
537
- }
538
-
539
- /**
540
- * 处理消息队列
541
- * @private
542
- */
543
- async _processQueue() {
544
- if (this._isProcessingQueue || this._messageQueue.length === 0) {
545
- return
546
- }
547
-
548
- this._isProcessingQueue = true
549
-
550
- // 强制设置为 idle,确保 this.chat() 能执行
551
- this._status = 'idle'
552
-
553
- while (this._messageQueue.length > 0) {
554
- const item = this._messageQueue.shift()
555
- try {
556
- const result = await this.chat(item.message, item.options)
557
- item.resolve(result)
558
- } catch (err) {
559
- item.reject(err)
560
- }
561
- }
562
-
563
- this._isProcessingQueue = false
564
- }
565
-
566
- /**
567
- * 发送消息(流式)
568
- */
569
- async *chatStream(message, options = {}) {
570
- if (this._status === 'busy') {
571
- throw new Error('Agent is busy')
572
- }
573
-
574
- // 允许从 error 状态重试
575
- if (this._status === 'error') {
576
- this._status = 'idle'
577
- }
578
-
579
- this._status = 'busy'
580
- this.emit('status', { status: 'busy' })
581
-
582
- try {
583
- // 检查是否有待处理的系统通知(调度 + 思考)
584
- const notifications = this._getAllPendingNotifications()
585
- let enhancedMessage = message
586
- if (notifications.length > 0) {
587
- enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`
588
- }
589
-
590
- this._syncTools()
591
-
592
- yield* this._chatHandler.chatStream(enhancedMessage, options)
593
- this._status = 'idle'
594
- this.emit('status', { status: 'idle' })
595
-
596
- // 处理队列中的下一条消息
597
- setImmediate(() => this._processQueue())
598
- } catch (err) {
599
- this._status = 'error'
600
- this.emit('status', { status: 'error', error: err.message })
601
-
602
- // 发生错误时也要处理队列
603
- setImmediate(() => this._processQueue())
604
-
605
- throw err
606
- }
607
- }
608
-
609
- /**
610
- * 设置元数据
611
- */
612
- setMetadata(keyOrObj, value) {
613
- if (typeof keyOrObj === 'string') {
614
- this._metadata.set(keyOrObj, value)
615
- } else if (keyOrObj && typeof keyOrObj === 'object') {
616
- for (const [key, val] of Object.entries(keyOrObj)) {
617
- this._metadata.set(key, val)
618
- }
619
- }
620
- this._refreshContext()
621
- return this
622
- }
623
-
624
- /**
625
- * 获取元数据
626
- */
627
- getMetadata(key) {
628
- return this._metadata.get(key)
629
- }
630
-
631
- /**
632
- * 删除元数据
633
- */
634
- deleteMetadata(key) {
635
- this._metadata.delete(key)
636
- this._refreshContext()
637
- return this
638
- }
639
-
640
- /**
641
- * 清空元数据
642
- */
643
- clearMetadata() {
644
- this._metadata.clear()
645
- this._refreshContext()
646
- return this
647
- }
648
-
649
- /**
650
- * 清空对话历史
651
- */
652
- clearHistory() {
653
- if (this._chatHandler) {
654
- this._chatHandler.clearHistory()
655
- }
656
- return this
657
- }
658
-
659
- /**
660
- * 获取状态
661
- */
662
- getStatus() {
663
- return this._status
664
- }
665
-
666
- /**
667
- * 重置状态(从卡住状态恢复)
668
- */
669
- resetStatus() {
670
- this._status = 'idle'
671
- this.emit('status', { status: 'idle' })
672
- return this
673
- }
674
-
675
- /**
676
- * 销毁 Agent
677
- */
678
- destroy() {
679
- if (this._chatHandler) {
680
- this._chatHandler.destroy()
681
- }
682
- this._tools.clear()
683
- this.removeAllListeners()
684
- this.emit('destroyed')
685
- }
686
- }
687
-
688
- module.exports = { Agent }
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 os = require('os');
10
+
11
+ class Agent extends EventEmitter {
12
+ /**
13
+ * @param {Framework} framework - 框架实例
14
+ * @param {Object} config - 配置
15
+ * @param {string} [config.name] - Agent 名称
16
+ * @param {string} [config.systemPrompt] - 系统提示
17
+ * @param {string} [config.sharedPrompt] - 共享提示模板,支持 {{VAR}} 占位符
18
+ * @param {Object} [config.metadata] - 元数据,注入到 sharedPrompt
19
+ * @param {boolean} [config.enableToolRouting=true] - 是否启用工具路由
20
+ */
21
+ constructor(framework, config = {}) {
22
+ super();
23
+
24
+ this.framework = framework;
25
+ this.config = config;
26
+
27
+ this.name = config.name || 'Agent';
28
+ this.model = config.model || 'deepseek-chat';
29
+ this.apiKey = config.apiKey;
30
+ this.baseURL = config.baseURL;
31
+ this.provider = config.provider || 'deepseek';
32
+ this.providerOptions = config.providerOptions || {};
33
+ this.providerOptions.maxOutputTokens = 8192;
34
+ this.providerOptions.temperature = 0.3; // 降低 temperature 减少生成错误 JSON 的概率
35
+ // 原始 system prompt
36
+ this._originalPrompt =
37
+ config.systemPrompt ||
38
+ '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。';
39
+
40
+ // 共享提示模板
41
+ this._sharedPrompt = config.sharedPrompt || '';
42
+
43
+ // 元数据
44
+ const metadata = config.metadata || {};
45
+ this._metadata = new Map(Object.entries(metadata));
46
+
47
+ this._chatHandler = null;
48
+ this._tools = new Map();
49
+ this._status = 'idle';
50
+
51
+ // 子Agent管理
52
+ this._subAgents = new Map();
53
+
54
+ // 消息队列(用于 pushMessage)
55
+ this._messageQueue = [];
56
+ this._isProcessingQueue = false;
57
+
58
+ // System prompt 构建器
59
+ this._systemPromptBuilder = new SystemPromptBuilder();
60
+ this._registerDefaultPromptParts();
61
+
62
+ // 处理后的 system prompt (带上下文)
63
+ this.systemPrompt = this._buildSystemPrompt();
64
+
65
+ // 初始化聊天处理器
66
+ this._initChatHandler();
67
+ }
68
+
69
+ /**
70
+ * 注册默认的系统提示词部分
71
+ * @private
72
+ */
73
+ _registerDefaultPromptParts() {
74
+ // 1. 原始 system prompt (优先级 100)
75
+ this._systemPromptBuilder.register('original-prompt', 100, () => this._originalPrompt);
76
+
77
+ // 2. 共享提示模板 (优先级 200)
78
+ this._systemPromptBuilder.register('shared-prompt', 200, () => {
79
+ if (this._sharedPrompt) {
80
+ return this._replacePlaceholders(this._sharedPrompt);
81
+ }
82
+ return null;
83
+ });
84
+
85
+ // 3. 元数据 (优先级 300)
86
+ this._systemPromptBuilder.register('metadata', 300, () => {
87
+ if (this._metadata.size === 0) {
88
+ return null;
89
+ }
90
+ const metaParts = ['【元数据】'];
91
+ for (const [key, value] of this._metadata) {
92
+ if (typeof value === 'object') {
93
+ metaParts.push(`- ${key}: ${JSON.stringify(value)}`);
94
+ } else {
95
+ metaParts.push(`- ${key}: ${value}`);
96
+ }
97
+ }
98
+ return metaParts.join('\n');
99
+ });
100
+
101
+ // 4. 工具列表 (优先级 400)
102
+ this._systemPromptBuilder.register('tools', 400, () => this._buildToolsDescription());
103
+
104
+ // 5. 技能列表 (优先级 500)
105
+ this._systemPromptBuilder.register('skills', 500, () => this._buildSkillsDescription());
106
+
107
+ // 6. 子Agent列表 (优先级 600)
108
+ this._systemPromptBuilder.register('subagents', 600, () => this._buildSubAgentsDescription());
109
+
110
+ // 7. 系统能力 (优先级 700)
111
+ this._systemPromptBuilder.register('capabilities', 700, () => this._buildCapabilitiesDescription());
112
+
113
+ // 8. 工具调用核心规则 (优先级 1000)
114
+ this._systemPromptBuilder.register('tool-core-rules', 1000, () => this._getToolCoreRules());
115
+ }
116
+
117
+ /**
118
+ * 获取元数据值
119
+ */
120
+ _getMetadataValue(key) {
121
+ // 优先从 metadata 获取
122
+ if (this._metadata.has(key)) {
123
+ return this._metadata.get(key);
124
+ }
125
+
126
+ // 内置变量
127
+ switch (key) {
128
+ case 'WORK_DIR':
129
+ case 'CWD':
130
+ return process.cwd();
131
+ case 'HOME_DIR':
132
+ return os.homedir();
133
+ case 'HOST_NAME':
134
+ return os.hostname();
135
+ case 'PLATFORM':
136
+ return process.platform;
137
+ case 'TIME':
138
+ return new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
139
+ case 'DATE':
140
+ return new Date().toISOString().split('T')[0];
141
+ default:
142
+ return `{{${key}}}`;
143
+ }
144
+ }
145
+
146
+ /**
147
+ * 替换 sharedPrompt 中的占位符
148
+ */
149
+ _replacePlaceholders(template) {
150
+ return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
151
+ return this._getMetadataValue(key);
152
+ });
153
+ }
154
+
155
+ /**
156
+ * 构建工具描述
157
+ */
158
+ _buildToolsDescription() {
159
+ if (this._tools.size === 0) {
160
+ return '';
161
+ }
162
+
163
+ // 需要排除的子Agent相关工具(它们通过专门的子Agent部分提供)
164
+ // const excludedTools = new Set(['subagent_call', 'subagent_list', 'subagent_reload']);
165
+
166
+ let desc = '【可用工具】\n';
167
+ for (const [name, tool] of this._tools) {
168
+ // 跳过没有描述的工具(对LLM无帮助)
169
+ if (!tool.description) continue;
170
+ // // 跳过子Agent相关工具(通过专门的子Agent部分提供)
171
+ // if (excludedTools.has(name)) continue;
172
+ // // 跳过子Agent委托工具(通过专门的子Agent部分提供)
173
+ // if (this._subAgents.has(name)) continue;
174
+ desc += `- ${name}: ${tool.description}\n`;
175
+ }
176
+ return desc.trim();
177
+ }
178
+
179
+ /**
180
+ * 构建技能描述
181
+ */
182
+ _buildSkillsDescription() {
183
+ const skillManager = this.framework.pluginManager.get('skill-manager');
184
+ if (!skillManager) {
185
+ return '';
186
+ }
187
+
188
+ const skills = skillManager.getAllSkills();
189
+ if (!skills || skills.length === 0) {
190
+ return '';
191
+ }
192
+
193
+ let desc = '【可用技能】\n';
194
+ for (const skill of skills) {
195
+ const name = skill.metadata?.name || skill.name || 'unknown';
196
+ const descText = skill.metadata?.description || '';
197
+ desc += `- ${name}: ${descText}\n`;
198
+ }
199
+ desc +=
200
+ '\n重要:当需要开发插件、执行专业任务时,必须先使用 loadSkill 工具加载对应技能,获取专业指导。';
201
+ return desc.trim();
202
+ }
203
+
204
+ /**
205
+ * 构建系统能力描述
206
+ */
207
+ _buildCapabilitiesDescription() {
208
+ const plugins = this.framework.pluginManager.getAll();
209
+ if (!plugins || plugins.length === 0) {
210
+ return '';
211
+ }
212
+
213
+ // 过滤出有描述的关键插件(排除内部插件)
214
+ const keyPlugins = plugins.filter((p) => {
215
+ const name = p.name;
216
+ // 排除默认配置插件和内部插件
217
+ return name !== 'defaults' && name !== 'agent';
218
+ });
219
+
220
+ if (keyPlugins.length === 0) {
221
+ return '';
222
+ }
223
+
224
+ let desc = '【系统能力】\n';
225
+ for (const plugin of keyPlugins) {
226
+ const name = plugin.instance?.name || plugin.name || 'unknown';
227
+ const description = plugin.instance?.description || '无描述';
228
+ desc += `- ${name}: ${description}\n`;
229
+ }
230
+
231
+ return desc.trim();
232
+ }
233
+
234
+ /**
235
+ * 构建子Agent描述
236
+ * 动态从配置文件读取每个子Agent的专业领域
237
+ */
238
+ _buildSubAgentsDescription() {
239
+ const subAgentManager = this.framework.pluginManager.get('subagent-manager');
240
+ if (!subAgentManager) {
241
+ return '';
242
+ }
243
+ const allSubAgents = subAgentManager.getAllSubAgents();
244
+ if (!allSubAgents || allSubAgents.length === 0) {
245
+ return '';
246
+ }
247
+
248
+ let desc = '【子 Agent 匹配表 - 优先使用】\n';
249
+
250
+ // 动态从配置文件读取每个子Agent的核心能力
251
+ for (const plugin of allSubAgents) {
252
+ const name = plugin.name;
253
+ const role = plugin.role;
254
+ const goal = plugin.description || '';
255
+
256
+ // 优先使用 SubAgentConfigManager 获取详细信息
257
+ const config = this.framework._subAgentConfigManager?.get(name);
258
+ if (config) {
259
+ const agentDesc = config.getDescription();
260
+ const skills = config.getSkills();
261
+ let info = agentDesc || role || goal || '子代理';
262
+ if (skills && skills.length > 0) {
263
+ info += ` (技能: ${skills.join(', ')})`;
264
+ }
265
+ desc += ` - ${name}: ${info}\n`;
266
+ } else {
267
+ // 回退到旧逻辑
268
+ desc += ` - ${name}: ${role || goal || '子代理'}\n`;
269
+ }
270
+ }
271
+
272
+ // 通用规则
273
+ desc += '\n【子Agent匹配规则 - 必须遵守】\n';
274
+ desc += ' - 根据上述【子 Agent 匹配表】,将任务委托给最匹配的子Agent处理\n';
275
+ desc += ' - 使用 subagent_call 工具并指定 agentName 来委托任务\n';
276
+ desc += ' - 只有当没有匹配的子Agent时,才直接调用工具\n';
277
+
278
+ return desc.trim();
279
+ }
280
+
281
+ /**
282
+ * 从配置文件动态读取子Agent的核心能力
283
+ * 支持 .json 和 .md 格式
284
+ * @private
285
+ */
286
+ _getSubAgentCapabilities(name) {
287
+ try {
288
+ const fs = require('fs');
289
+ const path = require('path');
290
+ const agentsDir = path.join(process.cwd(), '.agent', 'agents');
291
+
292
+ // 尝试多种文件格式
293
+ const possiblePaths = [
294
+ path.join(agentsDir, `${name}.md`),
295
+ path.join(agentsDir, `${name}.json`),
296
+ ];
297
+
298
+ let filePath = null;
299
+ for (const p of possiblePaths) {
300
+ if (fs.existsSync(p)) {
301
+ filePath = p;
302
+ break;
303
+ }
304
+ }
305
+
306
+ if (!filePath) {
307
+ return null;
308
+ }
309
+
310
+ const content = fs.readFileSync(filePath, 'utf-8');
311
+
312
+ // .json 格式
313
+ if (filePath.endsWith('.json')) {
314
+ const config = JSON.parse(content);
315
+ return this._extractCapabilitiesFromConfig(config);
316
+ }
317
+
318
+ // .md 格式(YAML front matter + markdown)
319
+ if (filePath.endsWith('.md')) {
320
+ return this._extractCapabilitiesFromMd(content);
321
+ }
322
+
323
+ return null;
324
+ } catch (e) {
325
+ return null;
326
+ }
327
+ }
328
+
329
+ /**
330
+ * 从 JSON 配置中提取核心能力
331
+ */
332
+ _extractCapabilitiesFromConfig(config) {
333
+ if (config.instructions) {
334
+ const match = config.instructions.match(/【核心能力】([\s\S]*?)(?=【|$)/);
335
+ if (match) {
336
+ const capabilities = match[1]
337
+ .split('\n')
338
+ .map((line) => line.replace(/^[·\-*]\s*/, '').trim())
339
+ .filter((line) => line && !line.startsWith('你是一个'))
340
+ .slice(0, 4)
341
+ .join('、');
342
+ return capabilities || config.description;
343
+ }
344
+ return config.description;
345
+ }
346
+ return config.description || null;
347
+ }
348
+
349
+ /**
350
+ * 从 .md 文件(YAML front matter)中提取核心能力
351
+ */
352
+ _extractCapabilitiesFromMd(mdContent) {
353
+ // 解析 YAML front matter
354
+ const frontMatterMatch = mdContent.match(/^---\n([\s\S]*?)\n---/);
355
+ if (!frontMatterMatch) {
356
+ return null;
357
+ }
358
+
359
+ const frontMatter = frontMatterMatch[1];
360
+ const config = {};
361
+
362
+ // 简单解析 YAML front matter
363
+ for (const line of frontMatter.split('\n')) {
364
+ const colonIndex = line.indexOf(':');
365
+ if (colonIndex > 0) {
366
+ const key = line.substring(0, colonIndex).trim();
367
+ let value = line.substring(colonIndex + 1).trim();
368
+ // 移除可能的引号
369
+ if ((value.startsWith('"') && value.endsWith('"')) ||
370
+ (value.startsWith("'") && value.endsWith("'"))) {
371
+ value = value.slice(1, -1);
372
+ }
373
+ config[key] = value;
374
+ }
375
+ }
376
+ // description 字段提取能力
377
+ if (config.description) {
378
+ const desc = config.description;
379
+ // 按逗号/顿号分隔
380
+ const parts = desc.split(/[,,、]/).map(s => s.trim());
381
+ // 取第一部分(通常是最核心的能力描述)
382
+ const firstPart = parts[0];
383
+ // 如果第一部分太长(说明是句子),取前50个字符
384
+ if (firstPart.length > 50) {
385
+ return firstPart.substring(0, 50).trim() + '...';
386
+ }
387
+ // 如果有多个部分,取前3个
388
+ if (parts.length > 1) {
389
+ return parts.slice(0, 3).join('、');
390
+ }
391
+ return firstPart;
392
+ }
393
+
394
+ return null;
395
+ }
396
+
397
+ _buildSystemPrompt() {
398
+ // 如果没变脏,返回缓存
399
+ if (!this._systemPromptDirty && this._systemPromptCache !== null) {
400
+ return this._systemPromptCache;
401
+ }
402
+
403
+ // 使用 builder 构建系统提示词
404
+ this._systemPromptCache = this._systemPromptBuilder.build();
405
+ this._systemPromptDirty = false;
406
+ return this._systemPromptCache;
407
+ }
408
+
409
+ /**
410
+ * 使 system prompt 缓存失效
411
+ * @private
412
+ */
413
+ _invalidateSystemPromptCache() {
414
+ this._systemPromptDirty = true;
415
+ // 同时使 builder 中所有部分失效
416
+ this._systemPromptBuilder.invalidateAll();
417
+ }
418
+
419
+ /**
420
+ * 注册自定义系统提示词部分(供插件使用)
421
+ * @param {string} name - 部分名称
422
+ * @param {number} priority - 优先级
423
+ * @param {Function} provider - 返回提示词内容的函数
424
+ */
425
+ registerPromptPart(name, priority, provider) {
426
+ this._systemPromptBuilder.register(name, priority, provider);
427
+ this._invalidateSystemPromptCache();
428
+ return this;
429
+ }
430
+
431
+ /**
432
+ * 注销系统提示词部分
433
+ * @param {string} name - 部分名称
434
+ */
435
+ unregisterPromptPart(name) {
436
+ this._systemPromptBuilder.unregister(name);
437
+ this._invalidateSystemPromptCache();
438
+ return this;
439
+ }
440
+
441
+ /**
442
+ * 使特定系统提示词部分失效
443
+ * @param {string} name - 部分名称
444
+ */
445
+ invalidatePromptPart(name) {
446
+ this._systemPromptBuilder.invalidate(name);
447
+ this._systemPromptDirty = true;
448
+ return this;
449
+ }
450
+
451
+ /**
452
+ * 获取工具调用核心规则
453
+ * @private
454
+ */
455
+ _getToolCoreRules() {
456
+ return `【工具调用核心规则】
457
+ 1. **子Agent优先**:任务匹配子Agent专业领域时,**必须优先使用** 使用 subagent_call 工具并指定 agentName 委托给对应子Agent处理,而不是直接调用工具。只有当没有匹配的子Agent时,才直接调用工具。
458
+ 2. **必须先调用工具再回复**:当问题需要信息、操作或计算时,必须调用工具获取真实结果后才能回答。禁止在未调用工具的情况下直接给出答案。
459
+ 3. **禁止编造数据**:不许捏造用户、订单、任务、文件、内容等任何数据。所有数据必须通过工具获取。
460
+ 4. **工具优先**:可用工具列表会提供,格式为 toolName(toolArgs)。不确定用哪个工具时,优先调用可能相关的工具。
461
+ 5. **结果导向**:调用工具后,基于返回结果回答,不要重复工具的内部实现细节。
462
+ 6. **多步骤任务**:复杂任务拆解为多个工具调用,逐步完成,每步基于结果决定下一步。
463
+
464
+
465
+ 【响应规范】
466
+ - 直接给出结论或结果,不说"我需要..."、"我建议..."等铺垫话术
467
+ - 如果工具返回错误,说明错误原因并给出解决建议
468
+ - 如果信息不足,先调用工具获取必要信息,不要假设或猜测
469
+
470
+ 【禁止事项】
471
+ - 不调用工具就直接回答
472
+ - 编造不存在的数据、文件、订单、用户等信息
473
+ - 回复含糊不清,让用户无法确定答案是否正确`;
474
+ }
475
+
476
+ /**
477
+ * 刷新上下文
478
+ */
479
+ _refreshContext() {
480
+ this.systemPrompt = this._buildSystemPrompt();
481
+ if (this._chatHandler) {
482
+ this._chatHandler.setSystemPrompt(this.systemPrompt);
483
+ }
484
+ }
485
+
486
+ /**
487
+ * 初始化聊天处理器
488
+ * @private
489
+ */
490
+ _initChatHandler() {
491
+ let aiClient = null;
492
+ const aiPlugin = this.framework.pluginManager.get('ai');
493
+ if (aiPlugin) {
494
+ aiClient = aiPlugin.getAIClient();
495
+ }
496
+
497
+ this._chatHandler = new AgentChatHandler(this, {
498
+ model: this.model,
499
+ provider: this.provider,
500
+ apiKey: this.apiKey,
501
+ baseURL: this.baseURL,
502
+ providerOptions: this.providerOptions,
503
+ // 上下文压缩配置
504
+ maxContextTokens: this.config.maxContextTokens,
505
+ compressionThreshold: this.config.compressionThreshold,
506
+ keepRecentMessages: this.config.keepRecentMessages,
507
+ enableSmartCompress: this.config.enableSmartCompress,
508
+ });
509
+
510
+ if (aiClient) {
511
+ this._chatHandler.setAIClient(aiClient);
512
+ }
513
+
514
+ // 转发事件
515
+ this._chatHandler.on('message', (msg) => this.emit('message', msg));
516
+ this._chatHandler.on('chunk', (chunk) => this.emit('chunk', chunk));
517
+ this._chatHandler.on('tool-call', (tool) => this.emit('tool-call', tool));
518
+ this._chatHandler.on('tool-result', (result) => this.emit('tool-result', result));
519
+ this._chatHandler.on('error', (err) => this.emit('error', err));
520
+
521
+ this._syncTools();
522
+ }
523
+
524
+ /**
525
+ * 设置系统提示
526
+ */
527
+ setSystemPrompt(prompt) {
528
+ this._originalPrompt = prompt;
529
+ this.systemPrompt = this._buildSystemPrompt();
530
+ if (this._chatHandler) {
531
+ this._chatHandler.setSystemPrompt(this.systemPrompt);
532
+ }
533
+ return this;
534
+ }
535
+
536
+ /**
537
+ * 注册工具到 Agent
538
+ */
539
+ registerTool(tool) {
540
+ this._tools.set(tool.name, tool);
541
+ this._invalidateSystemPromptCache();
542
+ if (this._chatHandler) {
543
+ this._chatHandler.registerTool(tool);
544
+ }
545
+ this._refreshContext();
546
+ return this;
547
+ }
548
+
549
+ /**
550
+ * 获取已注册工具
551
+ */
552
+ getTools() {
553
+ return Array.from(this._tools.values());
554
+ }
555
+
556
+ /**
557
+ * 同步框架中的工具到 Agent
558
+ * @private
559
+ */
560
+ _syncTools() {
561
+ if (this.framework.toolRegistry.size() > 0) {
562
+ for (const tool of this.framework.getTools()) {
563
+ if (!this._tools.has(tool.name)) {
564
+ this.registerTool(tool);
565
+ }
566
+ }
567
+ }
568
+ }
569
+
570
+ /**
571
+ * 注册子Agent
572
+ * @param {string} name - 子Agent名称
573
+ * @param {Agent} agent - 子Agent实例
574
+ * @param {string} role - 角色描述
575
+ * @param {string} goal - 目标描述
576
+ */
577
+ registerSubAgent(name, agent, role, goal) {
578
+ this._subAgents.set(name, { agent, role, goal });
579
+ this._invalidateSystemPromptCache();
580
+ this._refreshContext();
581
+ return this;
582
+ }
583
+
584
+ /**
585
+ * 注销子Agent
586
+ */
587
+ unregisterSubAgent(name) {
588
+ this._subAgents.delete(name);
589
+ this._invalidateSystemPromptCache();
590
+ this._refreshContext();
591
+ return this;
592
+ }
593
+
594
+ /**
595
+ * 获取所有子Agent
596
+ */
597
+ getSubAgents() {
598
+ return this._subAgents;
599
+ }
600
+
601
+ /**
602
+ * 获取待处理的调度通知并清除(下次不再重复显示)
603
+ */
604
+ _getAndClearSchedulerNotifications() {
605
+ try {
606
+ const scheduler = this.framework.pluginManager.get('scheduler');
607
+ if (scheduler && scheduler.instance && scheduler.instance.getPendingNotifications) {
608
+ const results = scheduler.instance.getPendingNotifications();
609
+ if (results.length > 0) {
610
+ const notifications = results.slice(-5).reverse(); // 最多5条,最新的在前
611
+ // 清除已发送的通知
612
+ if (scheduler.instance.clearDeliveredNotifications) {
613
+ scheduler.instance.clearDeliveredNotifications(notifications.length);
614
+ }
615
+ return notifications;
616
+ }
617
+ }
618
+ } catch (err) {
619
+ // 忽略错误,避免影响主流程
620
+ }
621
+ return [];
622
+ }
623
+
624
+ /**
625
+ * 获取待处理的思考结果并清除
626
+ */
627
+ _getAndClearThinkNotifications() {
628
+ try {
629
+ const think = this.framework.pluginManager.get('think');
630
+ if (think && think.instance && think.instance.getPendingThoughts) {
631
+ const thoughts = think.instance.getPendingThoughts();
632
+ if (thoughts.length > 0) {
633
+ return thoughts.slice(-5).reverse(); // 最多5条,最新的在前
634
+ }
635
+ }
636
+ } catch (err) {
637
+ // 忽略错误,避免影响主流程
638
+ }
639
+ return [];
640
+ }
641
+
642
+ /**
643
+ * 获取所有待处理的系统通知(调度 + 思考)
644
+ */
645
+ _getAllPendingNotifications() {
646
+ const notifications = [];
647
+
648
+ // 调度通知
649
+ const schedulerNotifs = this._getAndClearSchedulerNotifications();
650
+ for (const n of schedulerNotifs) {
651
+ notifications.push(
652
+ `【定时任务通知】\n任务: ${n.taskName || n.taskId}\n执行时间: ${n.executedAt}\n结果: ${n.result || n.action || '执行完成'}`
653
+ );
654
+ }
655
+
656
+ // 思考通知
657
+ const thinkNotifs = this._getAndClearThinkNotifications();
658
+ for (const t of thinkNotifs) {
659
+ notifications.push(
660
+ `【主动思考】\n模式: ${t.mode}\n主题: ${t.topic}\n结果: ${t.result || '思考完成'}`
661
+ );
662
+ }
663
+
664
+ return notifications;
665
+ }
666
+
667
+ /**
668
+ * 发送消息
669
+ */
670
+ async chat(message, options = {}) {
671
+ if (this._status === 'busy') {
672
+ throw new Error('Agent is busy');
673
+ }
674
+
675
+ if (this._status === 'error') {
676
+ this._status = 'idle';
677
+ }
678
+
679
+ this._status = 'busy';
680
+ this.emit('status', { status: 'busy' });
681
+
682
+ try {
683
+ // 检查是否有待处理的系统通知(调度 + 思考)
684
+ const notifications = this._getAllPendingNotifications();
685
+ let enhancedMessage = message;
686
+ if (notifications.length > 0) {
687
+ enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
688
+ }
689
+
690
+ this._syncTools();
691
+
692
+ const result = await this._chatHandler.chat(enhancedMessage, options);
693
+ this._status = 'idle';
694
+ this.emit('status', { status: 'idle' });
695
+
696
+ // 处理队列中的下一条消息
697
+ setImmediate(() => this._processQueue());
698
+
699
+ return result;
700
+ } catch (err) {
701
+ this._status = 'error';
702
+ this.emit('status', { status: 'error', error: err.message });
703
+
704
+ // 发生错误时也要处理队列
705
+ setImmediate(() => this._processQueue());
706
+
707
+ throw err;
708
+ }
709
+ }
710
+
711
+ /**
712
+ * 推送消息(自动继承当前 sessionId 上下文,自动排队)
713
+ * 工具中调用此方法,自动带上当前执行上下文的 sessionId
714
+ * 如果 agent 忙碌,消息会进入队列等待
715
+ * @param {string|Object} message - 消息
716
+ * @param {Object} options - 选项 { maxSteps }
717
+ * @returns {Promise<{success: boolean, message: string, stepCount: number}>}
718
+ */
719
+ async pushMessage(message, options = {}) {
720
+ // 自动从执行上下文获取 sessionId
721
+ const ctx = this.framework.getExecutionContext();
722
+ if (ctx?.sessionId && !options.sessionId) {
723
+ options.sessionId = ctx.sessionId;
724
+ }
725
+
726
+ // 如果忙碌,进入队列等待
727
+ if (this._status === 'busy') {
728
+ const queuedItem = { message, options, resolve: null, reject: null };
729
+ const promise = new Promise((resolve, reject) => {
730
+ queuedItem.resolve = resolve;
731
+ queuedItem.reject = reject;
732
+ });
733
+ this._messageQueue.push(queuedItem);
734
+ // Agent busy, message queued
735
+ return promise;
736
+ }
737
+
738
+ // 空闲则直接处理
739
+ return this.chat(message, options);
740
+ }
741
+
742
+ /**
743
+ * 处理消息队列
744
+ * @private
745
+ */
746
+ async _processQueue() {
747
+ if (this._isProcessingQueue || this._messageQueue.length === 0) {
748
+ return;
749
+ }
750
+
751
+ this._isProcessingQueue = true;
752
+
753
+ // 强制设置为 idle,确保 this.chat() 能执行
754
+ this._status = 'idle';
755
+
756
+ while (this._messageQueue.length > 0) {
757
+ const item = this._messageQueue.shift();
758
+ try {
759
+ const result = await this.chat(item.message, item.options);
760
+ item.resolve(result);
761
+ } catch (err) {
762
+ item.reject(err);
763
+ }
764
+ }
765
+
766
+ this._isProcessingQueue = false;
767
+ }
768
+
769
+ /**
770
+ * 发送消息(流式)
771
+ */
772
+ async *chatStream(message, options = {}) {
773
+ if (this._status === 'busy') {
774
+ throw new Error('Agent is busy');
775
+ }
776
+
777
+ // 允许从 error 状态重试
778
+ if (this._status === 'error') {
779
+ this._status = 'idle';
780
+ }
781
+
782
+ this._status = 'busy';
783
+ this.emit('status', { status: 'busy' });
784
+
785
+ try {
786
+ // 检查是否有待处理的系统通知(调度 + 思考)
787
+ const notifications = this._getAllPendingNotifications();
788
+ let enhancedMessage = message;
789
+ if (notifications.length > 0) {
790
+ enhancedMessage = `【系统通知】\n${notifications.join('\n\n')}\n\n---\n用户消息: ${message}`;
791
+ }
792
+
793
+ this._syncTools();
794
+
795
+ yield* this._chatHandler.chatStream(enhancedMessage, options);
796
+ this._status = 'idle';
797
+ this.emit('status', { status: 'idle' });
798
+
799
+ // 处理队列中的下一条消息
800
+ setImmediate(() => this._processQueue());
801
+ } catch (err) {
802
+ this._status = 'error';
803
+ this.emit('status', { status: 'error', error: err.message });
804
+
805
+ // 发生错误时也要处理队列
806
+ setImmediate(() => this._processQueue());
807
+
808
+ throw err;
809
+ }
810
+ }
811
+
812
+ /**
813
+ * 设置元数据
814
+ */
815
+ setMetadata(keyOrObj, value) {
816
+ if (typeof keyOrObj === 'string') {
817
+ this._metadata.set(keyOrObj, value);
818
+ } else if (keyOrObj && typeof keyOrObj === 'object') {
819
+ for (const [key, val] of Object.entries(keyOrObj)) {
820
+ this._metadata.set(key, val);
821
+ }
822
+ }
823
+ this._invalidateSystemPromptCache();
824
+ this._refreshContext();
825
+ return this;
826
+ }
827
+
828
+ /**
829
+ * 获取元数据
830
+ */
831
+ getMetadata(key) {
832
+ return this._metadata.get(key);
833
+ }
834
+
835
+ /**
836
+ * 删除元数据
837
+ */
838
+ deleteMetadata(key) {
839
+ this._metadata.delete(key);
840
+ this._refreshContext();
841
+ return this;
842
+ }
843
+
844
+ /**
845
+ * 清空元数据
846
+ */
847
+ clearMetadata() {
848
+ this._metadata.clear();
849
+ this._refreshContext();
850
+ return this;
851
+ }
852
+
853
+ /**
854
+ * 清空对话历史
855
+ */
856
+ clearHistory() {
857
+ if (this._chatHandler) {
858
+ this._chatHandler.clearHistory();
859
+ }
860
+ return this;
861
+ }
862
+
863
+ /**
864
+ * 获取状态
865
+ */
866
+ getStatus() {
867
+ return this._status;
868
+ }
869
+
870
+ /**
871
+ * 重置状态(从卡住状态恢复)
872
+ */
873
+ resetStatus() {
874
+ this._status = 'idle';
875
+ this.emit('status', { status: 'idle' });
876
+ return this;
877
+ }
878
+
879
+ /**
880
+ * 销毁 Agent
881
+ */
882
+ destroy() {
883
+ if (this._chatHandler) {
884
+ this._chatHandler.destroy();
885
+ }
886
+ this._tools.clear();
887
+ this.removeAllListeners();
888
+ this.emit('destroyed');
889
+ }
890
+ }
891
+
892
+ module.exports = { Agent };