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
@@ -1,786 +1,846 @@
1
- /**
2
- * SubAgent 子Agent插件
3
- * 创建具有独立工具集的子Agent,用于分工处理不同领域的任务
4
- */
5
-
6
- const fs = require('fs')
7
- const path = require('path')
8
- const { Plugin } = require('../src/core/plugin-base')
9
- const { z } = require('zod')
10
- const { Agent } = require('../src/core/agent')
11
-
12
- class SubAgentPlugin extends Plugin {
13
- constructor(config = {}) {
14
- super()
15
- this.name = config.name
16
- this.version = '1.0.0'
17
- this.description = config.description || `子Agent: ${config.name}`
18
- this.priority = 10
19
-
20
- this.system = true
21
-
22
- // 子Agent配置
23
- // tools: { toolName: toolFn } 自定义工具(只属于此子Agent)
24
- // parentTools: ['read_file'] 从父Agent继承的工具名称列表
25
- this.config = {
26
- name: config.name, // 子Agent名称
27
- role: config.role || config.name, // 角色描述
28
- description: config.description || '', // 供主Agent智能选择
29
- tools: config.tools || {}, // 自定义工具 { name: toolDef }
30
- parentTools: config.parentTools || [], // 从父Agent继承的工具名称列表
31
- llmConfig: config.llmConfig || null // 独立LLM配置
32
- }
33
-
34
- this._framework = null
35
- this._agent = null
36
- this._parentAgent = null
37
- }
38
-
39
- install(framework) {
40
- this._framework = framework
41
- return this
42
- }
43
-
44
- start(framework) {
45
- // 创建子Agent(可能需要等待父agent准备好)
46
- this._createSubAgent()
47
-
48
- // 注册委托工具到主Agent(通过framework获取父agent)
49
- this._registerDelegateTool()
50
-
51
- return this
52
- }
53
-
54
- /**
55
- * 创建子Agent
56
- */
57
- _createSubAgent() {
58
- // 获取父Agent(主Agent)
59
- const parentAgent = this._getParentAgent()
60
- if (!parentAgent) {
61
- // 父agent还没创建,监听事件等其创建
62
- if (this._framework) {
63
- const framework = this._framework
64
- framework.on('agent:created', (agent) => {
65
- if (framework._mainAgent && agent === framework._mainAgent) {
66
- // agent已创建,重新尝试创建子agent
67
- this._doCreateSubAgent(agent)
68
- // 注册委托工具
69
- this._registerDelegateTool()
70
- }
71
- })
72
- }
73
- return
74
- }
75
-
76
- this._doCreateSubAgent(parentAgent)
77
- }
78
-
79
- /**
80
- * 实际执行创建子Agent
81
- */
82
- _doCreateSubAgent(parentAgent) {
83
- // 避免重复创建
84
- if (this._agent) {
85
- return
86
- }
87
-
88
- // 获取从父Agent继承的工具
89
- const parentTools = this._getParentTools(parentAgent)
90
-
91
- // 确定LLM配置
92
- const aiPlugin = this._framework.pluginManager.get('ai')
93
- const llmConfig = this.config.llmConfig || (aiPlugin ? aiPlugin.getConfig() : {})
94
-
95
- // 创建子Agent
96
- this._agent = new Agent(this._framework, {
97
- name: this.config.name,
98
- systemPrompt: this._buildSystemPrompt(),
99
- model: llmConfig.model,
100
- provider: llmConfig.provider,
101
- apiKey: llmConfig.apiKey,
102
- baseURL: llmConfig.baseURL
103
- })
104
-
105
- // 注册从父Agent继承的工具
106
- for (const tool of parentTools) {
107
- this._framework.registerTool(tool)
108
- }
109
-
110
- // 注册自定义工具(只属于此子Agent,不污染全局)
111
- // tools 格式: { toolName: toolDef }
112
- if (this.config.tools && typeof this.config.tools === 'object') {
113
- for (const [toolName, toolDef] of Object.entries(this.config.tools)) {
114
- const tool = typeof toolDef === 'function' ? toolDef() : toolDef
115
- if (typeof tool === 'object' && tool.name) {
116
- this._framework.registerTool(tool)
117
- } else {
118
- // 假设是简化的工具定义,需要补充 name
119
- this._framework.registerTool({ name: toolName, ...tool })
120
- }
121
- }
122
- }
123
-
124
- // 保存父Agent引用
125
- this._parentAgent = parentAgent
126
-
127
- // 注册子Agent到父Agent
128
- parentAgent.registerSubAgent(this.config.name, this._agent, this.config.role, this.config.description)
129
-
130
- // 监听子Agent的chunk事件并转发给父Agent
131
- this._agent.on('chunk', (chunk) => {
132
- chunk.fromSubAgent = this.config.name
133
- parentAgent.emit('chunk', chunk)
134
- })
135
-
136
- const parentToolNames = parentTools.map(t => t.name)
137
- const customToolNames = Object.keys(this.config.tools || {})
138
- //console.log(`[SubAgent:${this.config.name}] Created with ${parentToolNames.length} parent tools + ${customToolNames.length} custom tools`)
139
- // if (parentToolNames.length > 0) {
140
- // console.log(` Parent tools: ${parentToolNames.join(', ')}`)
141
- // }
142
- // if (customToolNames.length > 0) {
143
- // console.log(` Custom tools: ${customToolNames.join(', ')}`)
144
- // }
145
- }
146
-
147
- /**
148
- * 获取父Agent
149
- */
150
- _getParentAgent() {
151
- // 优先使用外部传入的获取器
152
- if (this.config._parentAgentGetter) {
153
- return this.config._parentAgentGetter()
154
- }
155
-
156
- // 尝试从framework获取主agent
157
- // 在foliko中,主agent通常是通过framework.createAgent创建的
158
- if (this._framework._mainAgent) {
159
- return this._framework._mainAgent
160
- }
161
-
162
- // 查找最后一个创建的agent作为父agent
163
- const agents = this._framework._agents || []
164
- if (agents.length > 0) {
165
- return agents[agents.length - 1]
166
- }
167
-
168
- return null
169
- }
170
-
171
- /**
172
- * 获取从父Agent继承的工具
173
- */
174
- _getParentTools(parentAgent) {
175
- const allTools = parentAgent.getTools ? parentAgent.getTools() : []
176
- const toolMap = new Map(allTools.map(t => [t.name, t]))
177
-
178
- // 如果没有指定 parentTools,返回全部
179
- if (!this.config.parentTools || this.config.parentTools.length === 0) {
180
- return allTools
181
- }
182
- // 过滤指定工具
183
- const filtered = []
184
- for (const toolName of this.config.parentTools) {
185
- const tool = toolMap.get(toolName)
186
- if (tool) {
187
- filtered.push(tool)
188
- }
189
- // else {
190
- // console.warn(`[SubAgent:${this.config.name}] Parent tool not found: ${toolName}`)
191
- // }
192
- }
193
-
194
- return filtered
195
- }
196
-
197
- /**
198
- * 构建系统提示
199
- */
200
- _buildSystemPrompt() {
201
- return `你是 ${this.config.role}。
202
-
203
- 角色描述:${this.config.description || '一个专业的子Agent'}
204
-
205
- 当你被调用时,你应该:
206
- 1. 仔细理解任务要求
207
- 2. 使用你的工具集完成任务
208
- 3. 返回完整的操作结果
209
-
210
- 重要:返回结果要简洁明确,只包含最终结果,不需要解释过程。`
211
- }
212
-
213
- /**
214
- * 注册委托工具到框架和主Agent
215
- */
216
- _registerDelegateTool() {
217
- const framework = this._framework
218
- if (!framework) return
219
-
220
- const agentName = this.config.name
221
- const role = this.config.role
222
-
223
- const toolDef = {
224
- name: agentName,
225
- description: `${role}:当需要${role}时,调用此工具执行任务。如:编译代码、运行测试、代码重构等。`,
226
- inputSchema: z.object({
227
- task: z.string().describe('给子Agent的具体任务描述')
228
- }),
229
- execute: async (args, fw) => {
230
- if (!this._agent) {
231
- return { error: `SubAgent ${agentName} not initialized` }
232
- }
233
-
234
- const parentAgent = fw._mainAgent
235
- if (!parentAgent) {
236
- return { error: `Parent agent not found` }
237
- }
238
-
239
- // 发射子Agent开始处理事件
240
- parentAgent.emit('subagent:chat:start', {
241
- parentAgent,
242
- subAgent: this._agent,
243
- subAgentName: agentName,
244
- task: args.task
245
- })
246
-
247
- try {
248
- const result = await this._agent.pushMessage(args.task)
249
- // 发射子Agent完成处理事件
250
- parentAgent.emit('subagent:chat:end', {
251
- parentAgent,
252
- subAgent: this._agent,
253
- subAgentName: agentName,
254
- result
255
- })
256
- return {
257
- agent: agentName,
258
- result: result.message || result.error || result,
259
- success: result.success !== false
260
- }
261
- } catch (err) {
262
- // 发射子Agent错误事件
263
- parentAgent.emit('subagent:error', {
264
- parentAgent,
265
- subAgent: this._agent,
266
- subAgentName: agentName,
267
- error: err.message
268
- })
269
- return {
270
- agent: agentName,
271
- error: err.message,
272
- success: false
273
- }
274
- }
275
- }
276
- }
277
-
278
- // 注册到框架(供后续创建的 Agent 同步)
279
- framework.registerTool(toolDef)
280
-
281
- // 如果主 Agent 已存在,直接注册到它
282
- if (framework._mainAgent) {
283
- framework._mainAgent.registerTool(toolDef)
284
- }
285
-
286
- //console.log(`[SubAgent:${this.config.name}] Delegate tool registered`)
287
- }
288
-
289
- /**
290
- * 获取子Agent实例
291
- */
292
- getAgent() {
293
- return this._agent
294
- }
295
-
296
- /**
297
- * 调用子Agent处理任务
298
- */
299
- async chat(task) {
300
- if (!this._agent) {
301
- throw new Error(`SubAgent ${this.config.name} not initialized`)
302
- }
303
- return this._agent.pushMessage(task)
304
- }
305
-
306
- reload(framework) {
307
- this._framework = framework
308
- this._createSubAgent()
309
- }
310
-
311
- uninstall(framework) {
312
- if (this._parentAgent) {
313
- this._parentAgent.unregisterSubAgent(this.config.name)
314
- }
315
- if (this._agent) {
316
- this._agent.destroy()
317
- this._agent = null
318
- }
319
- this._parentAgent = null
320
- this._framework = null
321
- }
322
- }
323
-
324
- /**
325
- * SubAgentManager - 管理多个子Agent
326
- */
327
- class SubAgentManagerPlugin extends Plugin {
328
- constructor(config = {}) {
329
- super()
330
- this.name = 'subagent-manager'
331
- this.version = '1.0.0'
332
- this.description = '子Agent管理器,统一管理多个子Agent'
333
- this.priority = 10
334
-
335
- this.config = {
336
- agentsDir: config.agentsDir || null, // 子Agent配置目录
337
- agents: config.agents || [] // 子Agent配置列表
338
- }
339
-
340
- this._framework = null
341
- this._subAgents = new Map()
342
- this._fileWatcher = null
343
- this._lastFileStates = new Map() // 记录文件状态用于检测变化
344
- }
345
-
346
- install(framework) {
347
- this._framework = framework
348
- return this
349
- }
350
-
351
- start(framework) {
352
- // 从 agentsDir 加载子Agent配置
353
- this._loadAgentsFromDir()
354
-
355
- // 创建所有配置的子Agent
356
- for (const agentConfig of this.config.agents) {
357
- const plugin = new SubAgentPlugin(agentConfig)
358
- plugin.install(framework)
359
- plugin.start(framework)
360
- this._subAgents.set(agentConfig.name, plugin)
361
- }
362
-
363
- // 注册管理工具
364
- // 如果主 Agent 已存在,直接注册到它(因为它不会自动同步框架工具)
365
- if (framework._mainAgent) {
366
- this._registerToolsToAgent(framework._mainAgent)
367
- }
368
- // 同时注册到框架(供后续创建的 Agent 同步)
369
- this._registerTools(framework)
370
-
371
- // 监听主 Agent 创建事件,为后续创建的主 Agent 注册工具
372
- framework.on('agent:created', (agent) => {
373
- if (framework._mainAgent && agent === framework._mainAgent) {
374
- this._registerToolsToAgent(agent)
375
- }
376
- })
377
-
378
- // 启动文件监控
379
- this._startFileWatcher()
380
-
381
- return this
382
- }
383
-
384
- /**
385
- * 注册管理工具到指定 Agent
386
- */
387
- _registerToolsToAgent(agent) {
388
- agent.registerTool({
389
- name: 'subagent_list',
390
- description: '列出所有子Agent',
391
- inputSchema: z.object({}),
392
- execute: async () => {
393
- const agents = Array.from(this._subAgents.values()).map(p => ({
394
- name: p.config.name,
395
- role: p.config.role,
396
- description: p.config.description,
397
- toolCount: p._agent ? p._agent.getTools().length : 0
398
- }))
399
- return { success: true, agents }
400
- }
401
- })
402
-
403
- agent.registerTool({
404
- name: 'subagent_call',
405
- description: '调用指定的子Agent处理任务',
406
- inputSchema: z.object({
407
- agentName: z.string().describe('子Agent名称'),
408
- task: z.string().describe('任务描述')
409
- }),
410
- execute: async (args) => {
411
- const plugin = this._subAgents.get(args.agentName)
412
- if (!plugin) {
413
- return { success: false, error: `SubAgent ${args.agentName} not found` }
414
- }
415
-
416
- try {
417
- const result = await plugin.pushMessage(args.task)
418
- return {
419
- success: true,
420
- agent: args.agentName,
421
- result: result.message || result,
422
- success: result.success !== false
423
- }
424
- } catch (err) {
425
- return { success: false, error: err.message }
426
- }
427
- }
428
- })
429
-
430
- agent.registerTool({
431
- name: 'subagent_reload',
432
- description: '重新加载子Agent配置(当新增或删除.agent/agents下的文件后使用)',
433
- inputSchema: z.object({}),
434
- execute: async () => {
435
- try {
436
- this.reload(this._framework)
437
- return { success: true, message: '子Agent配置已重新加载' }
438
- } catch (err) {
439
- return { success: false, error: err.message }
440
- }
441
- }
442
- })
443
-
444
- //console.log('[SubAgentManager] Management tools registered to agent')
445
- }
446
-
447
- /**
448
- * 注册管理工具到框架工具注册表
449
- */
450
- _registerTools(framework) {
451
- framework.registerTool({
452
- name: 'subagent_list',
453
- description: '列出所有子Agent',
454
- inputSchema: z.object({}),
455
- execute: async () => {
456
- const agents = Array.from(this._subAgents.values()).map(p => ({
457
- name: p.config.name,
458
- role: p.config.role,
459
- description: p.config.description,
460
- toolCount: p._agent ? p._agent.getTools().length : 0
461
- }))
462
- return { success: true, agents }
463
- }
464
- })
465
-
466
- framework.registerTool({
467
- name: 'subagent_call',
468
- description: '调用指定的子Agent处理任务',
469
- inputSchema: z.object({
470
- agentName: z.string().describe('子Agent名称'),
471
- task: z.string().describe('任务描述')
472
- }),
473
- execute: async (args) => {
474
- const plugin = this._subAgents.get(args.agentName)
475
- if (!plugin) {
476
- return { success: false, error: `SubAgent ${args.agentName} not found` }
477
- }
478
-
479
- try {
480
- const result = await plugin.pushMessage(args.task)
481
- return {
482
- success: true,
483
- agent: args.agentName,
484
- result: result.message || result,
485
- success: result.success !== false
486
- }
487
- } catch (err) {
488
- return { success: false, error: err.message }
489
- }
490
- }
491
- })
492
-
493
- framework.registerTool({
494
- name: 'subagent_reload',
495
- description: '重新加载子Agent配置(当新增或删除.agent/agents下的文件后使用)',
496
- inputSchema: z.object({}),
497
- execute: async () => {
498
- try {
499
- this.reload(this._framework)
500
- return { success: true, message: '子Agent配置已重新加载' }
501
- } catch (err) {
502
- return { success: false, error: err.message }
503
- }
504
- }
505
- })
506
-
507
- //console.log('[SubAgentManager] Management tools registered to framework')
508
- }
509
-
510
- /**
511
- * 从 agentsDir 目录加载子Agent配置
512
- */
513
- _loadAgentsFromDir() {
514
- const agentsDir = this.config.agentsDir
515
- //console.log('[SubAgentManager] _loadAgentsFromDir called, agentsDir:', agentsDir)
516
- if (!agentsDir || !fs.existsSync(agentsDir)) {
517
- console.log('[SubAgentManager] agentsDir not found or does not exist')
518
- return
519
- }
520
-
521
- const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
522
- //console.log('[SubAgentManager] Found entries:', entries.length)
523
-
524
- for (const entry of entries) {
525
- if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
526
- const baseName = entry.name.replace(/\.(js|json|md)$/, '')
527
- const filePath = path.join(agentsDir, entry.name)
528
-
529
- // 跳过与已有配置同名的
530
- if (this.config.agents.some(a => a.name === baseName)) {
531
- continue
532
- }
533
-
534
- try {
535
- let agentConfig
536
- if (entry.name.endsWith('.json')) {
537
- const content = fs.readFileSync(filePath, 'utf-8')
538
- agentConfig = JSON.parse(content)
539
- } else if (entry.name.endsWith('.md')) {
540
- // 解析 markdown 文件,提取 JSON 配置
541
- agentConfig = this._parseMarkdownConfig(filePath, baseName)
542
- //console.log('[SubAgentManager] Parsed md:', baseName, agentConfig)
543
- } else {
544
- // 清除缓存并加载
545
- delete require.cache[require.resolve(filePath)]
546
- const mod = require(filePath)
547
- agentConfig = typeof mod === 'function' ? mod() : mod
548
- }
549
-
550
- if (agentConfig && agentConfig.name) {
551
- agentConfig._fromDir = true
552
- this.config.agents.push(agentConfig)
553
- //console.log('[SubAgentManager] Loaded agent:', agentConfig.name)
554
- } else {
555
- console.warn('[SubAgentManager] Agent config has no name:', baseName, agentConfig)
556
- }
557
- } catch (err) {
558
- console.warn(`[SubAgentManager] Failed to load agent config from ${filePath}:`, err.message, err.stack)
559
- }
560
- }
561
- }
562
- }
563
-
564
- /**
565
- * 解析 markdown 文件中的配置
566
- * 支持格式:
567
- * ```json
568
- * { "name": "xxx", "role": "xxx" }
569
- * ```
570
- * 或直接用 frontmatter 格式
571
- */
572
- _parseMarkdownConfig(filePath, defaultName) {
573
- const content = fs.readFileSync(filePath, 'utf-8')
574
- //console.log('[SubAgentManager] _parseMarkdownConfig:', filePath)
575
-
576
- // 尝试从 code block 中提取 JSON
577
- const jsonMatch = content.match(/```(?:json)?\s*\n([\s\S]*?)\n\s*```/)
578
- if (jsonMatch) {
579
- try {
580
- const config = JSON.parse(jsonMatch[1].trim())
581
- //console.log('[SubAgentManager] Found JSON in code block')
582
- return config
583
- } catch (err) {
584
- // JSON 解析失败,继续
585
- }
586
- }
587
-
588
- // 尝试从 frontmatter 格式中提取
589
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/)
590
- if (frontmatterMatch) {
591
- //console.log('[SubAgentManager] Found frontmatter')
592
- const frontmatterContent = frontmatterMatch[1]
593
- const parsed = this._parseYamlLike(frontmatterContent)
594
- if (parsed && parsed.name) {
595
- //console.log('[SubAgentManager] Parsed frontmatter:', parsed)
596
- return { name: parsed.name || defaultName, ...parsed }
597
- }
598
- }
599
-
600
- // 从 markdown 内容中提取配置(key: value 格式)
601
- const config = { name: defaultName }
602
- const yamlMatch = content.match(/^(name|role|description|parentTools|tools):\s*(.+)$/m)
603
- if (yamlMatch) {
604
- config[yamlMatch[1]] = yamlMatch[2].trim()
605
- }
606
-
607
- // 如果没有找到配置,使用文件名作为 name
608
- return config
609
- }
610
-
611
- /**
612
- * 解析类似 YAML 的配置
613
- */
614
- _parseYamlLike(content) {
615
- const result = {}
616
- const lines = content.split('\n')
617
-
618
- for (const line of lines) {
619
- const match = line.match(/^(\w+):\s*(.+)$/)
620
- if (match) {
621
- const key = match[1]
622
- let value = match[2].trim()
623
-
624
- // 处理数组格式 [a, b, c] 或 [a b c]
625
- if (value.startsWith('[') && value.endsWith(']')) {
626
- value = value.slice(1, -1).split(/[,\s]+/).filter(Boolean)
627
- }
628
-
629
- result[key] = value
630
- }
631
- }
632
-
633
- return result
634
- }
635
-
636
- /**
637
- * 启动文件监控
638
- */
639
- _startFileWatcher() {
640
- const agentsDir = this.config.agentsDir
641
- if (!agentsDir || !fs.existsSync(agentsDir)) {
642
- return
643
- }
644
-
645
- // 记录初始文件状态
646
- this._updateFileStates()
647
-
648
- // 使用 fs.watch 监控目录变化
649
- this._fileWatcher = fs.watch(agentsDir, { recursive: false }, (eventType, filename) => {
650
- if (filename && (filename.endsWith('.js') || filename.endsWith('.json') || filename.endsWith('.md'))) {
651
- //console.log(`[SubAgentManager] Detected change in agents dir: ${eventType} - ${filename}`)
652
-
653
- // 防抖:延迟处理,等文件操作完成
654
- setTimeout(() => {
655
- this._checkAndReload()
656
- }, 500)
657
- }
658
- })
659
-
660
- //console.log(`[SubAgentManager] Watching agents dir for changes: ${agentsDir}`)
661
- }
662
-
663
- /**
664
- * 更新文件状态
665
- */
666
- _updateFileStates() {
667
- const agentsDir = this.config.agentsDir
668
- if (!agentsDir || !fs.existsSync(agentsDir)) {
669
- return
670
- }
671
-
672
- this._lastFileStates.clear()
673
- const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
674
-
675
- for (const entry of entries) {
676
- if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
677
- const filePath = path.join(agentsDir, entry.name)
678
- try {
679
- const stat = fs.statSync(filePath)
680
- this._lastFileStates.set(entry.name, {
681
- mtime: stat.mtime.getTime(),
682
- size: stat.size
683
- })
684
- } catch (err) {
685
- // 忽略
686
- }
687
- }
688
- }
689
- }
690
-
691
- /**
692
- * 检查并重载(如果有变化)
693
- */
694
- _checkAndReload() {
695
- const agentsDir = this.config.agentsDir
696
- if (!agentsDir || !fs.existsSync(agentsDir)) {
697
- return
698
- }
699
-
700
- const currentStates = new Map()
701
- const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
702
- let hasChanges = false
703
-
704
- // 检查当前文件
705
- for (const entry of entries) {
706
- if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
707
- const filePath = path.join(agentsDir, entry.name)
708
- try {
709
- const stat = fs.statSync(filePath)
710
- currentStates.set(entry.name, {
711
- mtime: stat.mtime.getTime(),
712
- size: stat.size
713
- })
714
-
715
- const lastState = this._lastFileStates.get(entry.name)
716
- if (!lastState || lastState.mtime !== stat.mtime.getTime() || lastState.size !== stat.size) {
717
- hasChanges = true
718
- }
719
- } catch (err) {
720
- // 忽略
721
- }
722
- }
723
- }
724
-
725
- // 检查删除的文件
726
- for (const [name] of this._lastFileStates) {
727
- if (!currentStates.has(name)) {
728
- hasChanges = true
729
- break
730
- }
731
- }
732
-
733
- if (hasChanges) {
734
- //console.log('[SubAgentManager] File changes detected, reloading...')
735
- this._updateFileStates()
736
- this.reload(this._framework)
737
- }
738
- }
739
-
740
- /**
741
- * 获取子Agent
742
- */
743
- getSubAgent(name) {
744
- const plugin = this._subAgents.get(name)
745
- return plugin ? plugin.getAgent() : null
746
- }
747
-
748
- reload(framework) {
749
- // 停止文件监控
750
- if (this._fileWatcher) {
751
- this._fileWatcher.close()
752
- this._fileWatcher = null
753
- }
754
-
755
- // 销毁旧的子Agent
756
- for (const plugin of this._subAgents.values()) {
757
- plugin.uninstall(framework)
758
- }
759
- this._subAgents.clear()
760
-
761
- // 清空从目录加载的配置,重新加载
762
- this.config.agents = this.config.agents.filter(a => !a._fromDir)
763
-
764
- // 重新创建
765
- this.start(framework)
766
- }
767
-
768
- uninstall(framework) {
769
- // 停止文件监控
770
- if (this._fileWatcher) {
771
- this._fileWatcher.close()
772
- this._fileWatcher = null
773
- }
774
-
775
- for (const plugin of this._subAgents.values()) {
776
- plugin.uninstall(framework)
777
- }
778
- this._subAgents.clear()
779
- this._framework = null
780
- }
781
- }
782
-
783
- module.exports = {
784
- SubAgentPlugin,
785
- SubAgentManagerPlugin
1
+ /**
2
+ * SubAgent 子Agent插件
3
+ * 创建具有独立工具集的子Agent,用于分工处理不同领域的任务
4
+ */
5
+
6
+ const fs = require('fs')
7
+ const path = require('path')
8
+ const { Plugin } = require('../src/core/plugin-base')
9
+ const { logger } = require('../src/utils/logger')
10
+ const log = logger.child('SubAgent')
11
+ const { z } = require('zod')
12
+ const { Agent } = require('../src/core/agent')
13
+
14
+ class SubAgentPlugin extends Plugin {
15
+ constructor(config = {}) {
16
+ super()
17
+ this.name = config.name
18
+ this.version = '1.0.0'
19
+ this.description = config.description || `子Agent: ${config.name}`
20
+ this.priority = 10
21
+
22
+ this.system = true
23
+
24
+ this.role= config.role || config.name
25
+ this.tools = config.tools || {}
26
+ this.parentTools = config.parentTools || []
27
+ this.llmConfig = config.llmConfig || null
28
+
29
+ // 子Agent配置
30
+ // tools: { toolName: toolFn } 自定义工具(只属于此子Agent
31
+ // parentTools: ['read_file'] 从父Agent继承的工具名称列表
32
+ this.config = {}
33
+
34
+ this._framework = null
35
+ this._agent = null
36
+ this._parentAgent = null
37
+ }
38
+
39
+ install(framework) {
40
+ this._framework = framework
41
+ return this
42
+ }
43
+
44
+ start(framework) {
45
+ // 创建子Agent(可能需要等待父agent准备好)
46
+ this._createSubAgent()
47
+
48
+ // 注册委托工具到主Agent(通过framework获取父agent)
49
+ this._registerDelegateTool()
50
+
51
+ return this
52
+ }
53
+
54
+ /**
55
+ * 创建子Agent
56
+ */
57
+ _createSubAgent() {
58
+ // 获取父Agent(主Agent)
59
+ const parentAgent = this._getParentAgent()
60
+ if (!parentAgent) {
61
+ // 父agent还没创建,监听事件等其创建
62
+ if (this._framework) {
63
+ this._framework.on('agent:created', (agent) => {
64
+ if (this._framework._mainAgent && agent === this._framework._mainAgent) {
65
+ // agent已创建,更新父agent引用
66
+ this._parentAgent = agent
67
+ // 重新尝试创建子agent
68
+ this._doCreateSubAgent(agent)
69
+ // 注册委托工具
70
+ this._registerDelegateTool()
71
+ }
72
+ })
73
+ }
74
+ return
75
+ }
76
+
77
+ this._doCreateSubAgent(parentAgent)
78
+ }
79
+
80
+ /**
81
+ * 实际执行创建子Agent
82
+ */
83
+ _doCreateSubAgent(parentAgent) {
84
+ // 避免重复创建
85
+ if (this._agent) {
86
+ return
87
+ }
88
+
89
+ // 获取从父Agent继承的工具
90
+ const parentTools = this._getParentTools(parentAgent)
91
+
92
+ // 确定LLM配置
93
+ const aiPlugin = this._framework.pluginManager.get('ai')
94
+ const llmConfig = this.llmConfig || (aiPlugin ? aiPlugin.getConfig() : {})
95
+
96
+
97
+ // 创建子Agent,使用完整的 md 文件内容作为系统提示词
98
+ this._agent = this._framework.createSubAgent({
99
+ name: this.name,
100
+ systemPrompt: this._getFullSystemPrompt(),
101
+ model: llmConfig.model,
102
+ provider: llmConfig.provider,
103
+ apiKey: llmConfig.apiKey,
104
+ baseURL: llmConfig.baseURL,
105
+ tools: this.tools||{}, // 自定义工具
106
+ parentTools: parentTools
107
+ })
108
+
109
+ // 注册从父Agent继承的工具
110
+ // for (const tool of parentTools) {
111
+ // this._framework.registerTool(tool)
112
+ // }
113
+
114
+ // Register custom tools (only for this subAgent, won't pollute global)
115
+ // tools format: { toolName: toolDef }
116
+
117
+ this._parentAgent = parentAgent
118
+
119
+ // 注册子Agent到父Agent
120
+ parentAgent.registerSubAgent(this.name, this._agent, this.role, this.description)
121
+
122
+ // 监听子Agent的chunk事件并转发给父Agent
123
+ this._agent.on('chunk', (chunk) => {
124
+ chunk.fromSubAgent = this.name
125
+ parentAgent.emit('chunk', chunk)
126
+ })
127
+ }
128
+
129
+ /**
130
+ * 获取父Agent
131
+ */
132
+ _getParentAgent() {
133
+ // 优先使用外部传入的获取器
134
+ if (this.config._parentAgentGetter) {
135
+ return this.config._parentAgentGetter()
136
+ }
137
+
138
+ // 尝试从framework获取主agent
139
+ if (this._framework._mainAgent) {
140
+ return this._framework._mainAgent
141
+ }
142
+
143
+ // 查找最后一个创建的agent作为父agent
144
+ const agents = this._framework._agents || []
145
+ if (agents.length > 0) {
146
+ return agents[agents.length - 1]
147
+ }
148
+
149
+ return null
150
+ }
151
+
152
+ /**
153
+ * 获取从父Agent继承的工具
154
+ */
155
+ _getParentTools(parentAgent) {
156
+ const allTools = parentAgent.getTools ? parentAgent.getTools() : []
157
+ const toolMap = new Map(allTools.map(t => [t.name, t]))
158
+
159
+ // 如果没有指定 parentTools,返回全部
160
+ if (!this.parentTools || this.parentTools.length === 0) {
161
+ return allTools
162
+ }
163
+ // 过滤指定工具
164
+ const filtered = []
165
+ for (const toolName of this.parentTools) {
166
+ const tool = toolMap.get(toolName)
167
+ if (tool) {
168
+ filtered.push(tool)
169
+ }
170
+ // else {
171
+ // console.warn(`[SubAgent:${this.config.name}] Parent tool not found: ${toolName}`)
172
+ // }
173
+ }
174
+
175
+ return filtered
176
+ }
177
+
178
+ /**
179
+ * 构建系统提示
180
+ */
181
+ _buildSystemPrompt() {
182
+ return `你是 ${this.role}。
183
+
184
+ 角色描述:${this.description || '一个专业的子Agent'}
185
+
186
+ 当你被调用时,你应该:
187
+ 1. 仔细理解任务要求
188
+ 2. 使用你的工具集完成任务
189
+ 3. 返回完整的操作结果
190
+
191
+ 重要:返回结果要简洁明确,只包含最终结果,不需要解释过程。`
192
+ }
193
+
194
+ /**
195
+ * 注册委托工具到框架和主Agent
196
+ */
197
+ _registerDelegateTool() {
198
+ const framework = this._framework
199
+ if (!framework) return
200
+
201
+ const agentName = this.name
202
+ const role = this.role
203
+
204
+ const toolDef = {
205
+ name: agentName,
206
+ description: `${role}:当需要${role}时,调用此工具执行任务。如:编译代码、运行测试、代码重构等。`,
207
+ inputSchema: z.object({
208
+ task: z.string().describe('给子Agent的具体任务描述')
209
+ }),
210
+ execute: async (args, fw) => {
211
+ if (!this._agent) {
212
+ return { error: `SubAgent ${agentName} not initialized` }
213
+ }
214
+
215
+ const parentAgent = fw._mainAgent
216
+ if (!parentAgent) {
217
+ return { error: `Parent agent not found` }
218
+ }
219
+
220
+ // 发射子Agent开始处理事件
221
+ parentAgent.emit('subagent:chat:start', {
222
+ parentAgent,
223
+ subAgent: this._agent,
224
+ subAgentName: agentName,
225
+ task: args.task
226
+ })
227
+
228
+ try {
229
+ const result = await this._agent.chat(args.task)
230
+ // 发射子Agent完成处理事件
231
+ parentAgent.emit('subagent:chat:end', {
232
+ parentAgent,
233
+ subAgent: this._agent,
234
+ subAgentName: agentName,
235
+ result
236
+ })
237
+ return {
238
+ agent: agentName,
239
+ result: result.message || result.error || result,
240
+ success: result.success !== false
241
+ }
242
+ } catch (err) {
243
+ // 发射子Agent错误事件
244
+ parentAgent.emit('subagent:error', {
245
+ parentAgent,
246
+ subAgent: this._agent,
247
+ subAgentName: agentName,
248
+ error: err.message
249
+ })
250
+ return {
251
+ agent: agentName,
252
+ error: err.message,
253
+ success: false
254
+ }
255
+ }
256
+ }
257
+ }
258
+
259
+ // 注册到框架(供后续创建的 Agent 同步)
260
+ // framework.registerTool(toolDef)
261
+
262
+ // // 如果主 Agent 已存在,直接注册到它
263
+ // if (framework._mainAgent) {
264
+ // framework._mainAgent.registerTool(toolDef)
265
+ // }
266
+
267
+ //console.log(`[SubAgent:${this.config.name}] Delegate tool registered`)
268
+ }
269
+
270
+ /**
271
+ * 获取子Agent实例
272
+ */
273
+ getAgent() {
274
+ return this._agent
275
+ }
276
+
277
+ /**
278
+ * 调用子Agent处理任务
279
+ * 延迟创建 Agent,使用完整的 md 文件内容作为系统提示词
280
+ */
281
+ async chat(task) {
282
+ // 延迟创建 Agent(如果尚未创建)
283
+ if (!this._agent) {
284
+ await this._createSubAgentForChat();
285
+ } else {
286
+ // 每次调用时更新系统提示词,确保使用最新的 md 文件内容
287
+ this._updateAgentSystemPrompt();
288
+ }
289
+ return this._agent.chat(task)
290
+ }
291
+
292
+ /**
293
+ * 创建用于聊天的高完整度 Agent
294
+ * 使用 SubAgentConfig 读取完整的 md 文件内容
295
+ */
296
+ async _createSubAgentForChat() {
297
+ const parentAgent = this._getParentAgent();
298
+ if (!parentAgent) {
299
+ throw new Error(`SubAgent ${this.name}: parent agent not found`);
300
+ }
301
+
302
+ // 使用 SubAgentConfig 获取完整的系统提示词
303
+ const systemPrompt = this._getFullSystemPrompt();
304
+ const parentTools = this._getParentTools(parentAgent)
305
+ // 获取 LLM 配置
306
+ const aiPlugin = this._framework.pluginManager.get('ai');
307
+ const llmConfig = this.llmConfig || (aiPlugin ? aiPlugin.getConfig() : {});
308
+
309
+ // 创建 Agent,使用完整的 md 内容作为系统提示词
310
+ this._agent = this._framework.createSubAgent({
311
+ name: this.name,
312
+ systemPrompt: systemPrompt,
313
+ model: llmConfig.model,
314
+ provider: llmConfig.provider,
315
+ apiKey: llmConfig.apiKey,
316
+ baseURL: llmConfig.baseURL,
317
+ tools: this.tools||{}, // 自定义工具
318
+ parentTools: parentTools
319
+ });
320
+
321
+ // 注册到父 Agent
322
+ this._parentAgent = parentAgent;
323
+ parentAgent.registerSubAgent(this.name, this._agent, this.role, this.description);
324
+ }
325
+
326
+ /**
327
+ * 获取完整的系统提示词(从 md 文件读取)
328
+ */
329
+ _getFullSystemPrompt() {
330
+ // 尝试从 SubAgentConfigManager 获取完整内容
331
+ const configManager = this._framework._subAgentConfigManager;
332
+ if (configManager) {
333
+ const config = configManager.get(this.name);
334
+ if (config) {
335
+ return config.getSystemPrompt();
336
+ }
337
+ }
338
+
339
+ // 回退到默认的 _buildSystemPrompt
340
+ return this._buildSystemPrompt();
341
+ }
342
+
343
+ /**
344
+ * 更新 Agent 的系统提示词
345
+ */
346
+ _updateAgentSystemPrompt() {
347
+ if (!this._agent) return;
348
+ const systemPrompt = this._getFullSystemPrompt();
349
+ this._agent.setSystemPrompt(systemPrompt);
350
+ }
351
+
352
+ reload(framework) {
353
+ this._framework = framework
354
+ this._createSubAgent()
355
+ }
356
+
357
+ uninstall(framework) {
358
+ if (this._parentAgent) {
359
+ this._parentAgent.unregisterSubAgent(this.name)
360
+ }
361
+ if (this._agent) {
362
+ this._agent.destroy()
363
+ this._agent = null
364
+ }
365
+ this._parentAgent = null
366
+ this._framework = null
367
+ }
368
+ }
369
+
370
+ /**
371
+ * SubAgentManager - 管理多个子Agent
372
+ */
373
+ class SubAgentManagerPlugin extends Plugin {
374
+ constructor(config = {}) {
375
+ super()
376
+ this.name = 'subagent-manager'
377
+ this.version = '1.0.0'
378
+ this.description = '子Agent管理器,统一管理多个子Agent'
379
+
380
+ this.systemPrompt= `你是一个子Agent管理器,负责管理多个子Agent。每个子Agent都有独立的工具集和角色描述。当需要处理特定任务时,你会选择合适的子Agent来执行。`
381
+
382
+ this.priority = 10
383
+ this.agents = config.agents || [] // 预定义的子Agent配置列表
384
+ this.config = {
385
+ agentsDir: config.agentsDir || null, // 子Agent配置目录
386
+ }
387
+
388
+ this._framework = null
389
+ this._subAgents = new Map()
390
+ this._fileWatcher = null
391
+ this._lastFileStates = new Map() // 记录文件状态用于检测变化
392
+ }
393
+
394
+ install(framework) {
395
+ this._framework = framework
396
+ return this
397
+ }
398
+
399
+ start(framework) {
400
+ // 从 agentsDir 加载子Agent配置
401
+ this._loadAgentsFromDir()
402
+
403
+ // 创建所有配置的子Agent
404
+ for (const agentConfig of this.agents) {
405
+ const plugin = new SubAgentPlugin(agentConfig)
406
+ plugin.install(framework)
407
+ plugin.start(framework)
408
+ this._subAgents.set(agentConfig.name, plugin)
409
+ }
410
+
411
+ // 注册管理工具
412
+ // 如果主 Agent 已存在,直接注册到它(因为它不会自动同步框架工具)
413
+ if (framework._mainAgent) {
414
+ this._registerToolsToAgent(framework._mainAgent)
415
+ }
416
+ // 同时注册到框架(供后续创建的 Agent 同步)
417
+ this._registerTools(framework)
418
+
419
+ // 监听主 Agent 创建事件,为后续创建的主 Agent 注册工具
420
+ framework.on('agent:created', (agent) => {
421
+ if (framework._mainAgent && agent === framework._mainAgent) {
422
+ this._registerToolsToAgent(agent)
423
+ }
424
+ })
425
+
426
+ // 启动文件监控
427
+ this._startFileWatcher()
428
+
429
+ return this
430
+ }
431
+
432
+ /**
433
+ * 注册管理工具到指定 Agent
434
+ */
435
+ _registerToolsToAgent(agent) {
436
+ agent.registerTool({
437
+ name: 'subagent_list',
438
+ description: '列出所有子Agent',
439
+ inputSchema: z.object({}),
440
+ execute: async () => {
441
+ const agents = Array.from(this._subAgents.values()).map(p => ({
442
+ name: p.name,
443
+ role: p.role,
444
+ description: p.description,
445
+ toolCount: p._agent ? p._agent.getTools().length : 0
446
+ }))
447
+ return { success: true, agents }
448
+ }
449
+ })
450
+
451
+ agent.registerTool({
452
+ name: 'subagent_call',
453
+ description: '调用指定的子Agent处理任务',
454
+ inputSchema: z.object({
455
+ agentName: z.string().describe('子Agent名称'),
456
+ task: z.string().describe('任务描述')
457
+ }),
458
+ execute: async (args) => {
459
+ const plugin = this._subAgents.get(args.agentName)
460
+ if (!plugin) {
461
+ return { success: false, error: `SubAgent ${args.agentName} not found` }
462
+ }
463
+
464
+ try {
465
+ const result = await plugin.chat(args.task)
466
+ return {
467
+ success: true,
468
+ agent: args.agentName,
469
+ result: result.message || result,
470
+ success: result.success !== false
471
+ }
472
+ } catch (err) {
473
+ return { success: false, error: err.message }
474
+ }
475
+ }
476
+ })
477
+
478
+ agent.registerTool({
479
+ name: 'subagent_reload',
480
+ description: '重新加载子Agent配置(当新增或删除.agent/agents下的文件后使用)',
481
+ inputSchema: z.object({}),
482
+ execute: async () => {
483
+ try {
484
+ this.reload(this._framework)
485
+ return { success: true, message: '子Agent配置已重新加载' }
486
+ } catch (err) {
487
+ return { success: false, error: err.message }
488
+ }
489
+ }
490
+ })
491
+
492
+ //log.info(' Management tools registered to agent')
493
+ }
494
+
495
+ /**
496
+ * 注册管理工具到框架工具注册表
497
+ */
498
+ _registerTools(framework) {
499
+ framework.registerTool({
500
+ name: 'subagent_list',
501
+ description: '列出所有子Agent',
502
+ inputSchema: z.object({}),
503
+ execute: async () => {
504
+ const agents = Array.from(this._subAgents.values()).map(p => ({
505
+ name: p.name,
506
+ role: p.role,
507
+ description: p.description,
508
+ toolCount: p._agent ? p._agent.getTools().length : 0
509
+ }))
510
+ return { success: true, agents }
511
+ }
512
+ })
513
+
514
+ framework.registerTool({
515
+ name: 'subagent_call',
516
+ description: '调用指定的子Agent处理任务',
517
+ inputSchema: z.object({
518
+ agentName: z.string().describe('子Agent名称'),
519
+ task: z.string().describe('任务描述')
520
+ }),
521
+ execute: async (args) => {
522
+ const plugin = this._subAgents.get(args.agentName)
523
+ if (!plugin) {
524
+ return { success: false, error: `SubAgent ${args.agentName} not found` }
525
+ }
526
+
527
+ try {
528
+ const result = await plugin.chat(args.task)
529
+ return {
530
+ success: true,
531
+ agent: args.agentName,
532
+ result: result.message || result,
533
+ success: result.success !== false
534
+ }
535
+ } catch (err) {
536
+ return { success: false, error: err.message }
537
+ }
538
+ }
539
+ })
540
+
541
+ framework.registerTool({
542
+ name: 'subagent_reload',
543
+ description: '重新加载子Agent配置(当新增或删除.agent/agents下的文件后使用)',
544
+ inputSchema: z.object({}),
545
+ execute: async () => {
546
+ try {
547
+ this.reload(this._framework)
548
+ return { success: true, message: '子Agent配置已重新加载' }
549
+ } catch (err) {
550
+ return { success: false, error: err.message }
551
+ }
552
+ }
553
+ })
554
+
555
+ //log.info(' Management tools registered to framework')
556
+ }
557
+
558
+ /**
559
+ * 从 agentsDir 目录加载子Agent配置
560
+ */
561
+ _loadAgentsFromDir() {
562
+ const agentsDir = this.config.agentsDir
563
+ //log.info(' _loadAgentsFromDir called, agentsDir:', agentsDir)
564
+ if (!agentsDir || !fs.existsSync(agentsDir)) {
565
+ log.info(' agentsDir not found or does not exist')
566
+ return
567
+ }
568
+
569
+ const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
570
+ //log.info(' Found entries:', entries.length)
571
+
572
+ for (const entry of entries) {
573
+ if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
574
+ const baseName = entry.name.replace(/\.(js|json|md)$/, '')
575
+ const filePath = path.join(agentsDir, entry.name)
576
+
577
+ // 跳过与已有配置同名的
578
+ if (this.agents.some(a => a.name === baseName)) {
579
+ continue
580
+ }
581
+
582
+ try {
583
+ let agentConfig
584
+ if (entry.name.endsWith('.json')) {
585
+ const content = fs.readFileSync(filePath, 'utf-8')
586
+ agentConfig = JSON.parse(content)
587
+ } else if (entry.name.endsWith('.md')) {
588
+ // 解析 markdown 文件,提取 JSON 配置
589
+ agentConfig = this._parseMarkdownConfig(filePath, baseName)
590
+ //log.info(' Parsed md:', baseName, agentConfig)
591
+ } else {
592
+ // 清除缓存并加载
593
+ delete require.cache[require.resolve(filePath)]
594
+ const mod = require(filePath)
595
+ agentConfig = typeof mod === 'function' ? mod() : mod
596
+ }
597
+
598
+ if (agentConfig && agentConfig.name) {
599
+ agentConfig._fromDir = true
600
+ this.agents.push(agentConfig)
601
+ //log.info(' Loaded agent:', agentConfig.name)
602
+ } else {
603
+ log.warn(' Agent config has no name:', baseName, agentConfig)
604
+ }
605
+ } catch (err) {
606
+ log.warn(` Failed to load agent config from ${filePath}:`, err.message, err.stack)
607
+ }
608
+ }
609
+ }
610
+ }
611
+
612
+ /**
613
+ * 解析 markdown 文件中的配置
614
+ * 支持格式:
615
+ * ```json
616
+ * { "name": "xxx", "role": "xxx" }
617
+ * ```
618
+ * 或直接用 frontmatter 格式
619
+ */
620
+ _parseMarkdownConfig(filePath, defaultName) {
621
+ const content = fs.readFileSync(filePath, 'utf-8')
622
+ //log.info(' _parseMarkdownConfig:', filePath)
623
+
624
+ // 尝试从 code block 中提取 JSON
625
+ const jsonMatch = content.match(/```(?:json)?\s*\n([\s\S]*?)\n\s*```/)
626
+ if (jsonMatch) {
627
+ try {
628
+ const config = JSON.parse(jsonMatch[1].trim())
629
+ //log.info(' Found JSON in code block')
630
+ return config
631
+ } catch (err) {
632
+ // JSON 解析失败,继续
633
+ }
634
+ }
635
+
636
+ // 尝试从 frontmatter 格式中提取
637
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/)
638
+ if (frontmatterMatch) {
639
+ //log.info(' Found frontmatter')
640
+ const frontmatterContent = frontmatterMatch[1]
641
+ const parsed = this._parseYamlLike(frontmatterContent)
642
+ if (parsed && parsed.name) {
643
+ //log.info(' Parsed frontmatter:', parsed)
644
+ return { name: parsed.name || defaultName, ...parsed }
645
+ }
646
+ }
647
+
648
+ // markdown 内容中提取配置(key: value 格式)
649
+ const config = { name: defaultName }
650
+ const yamlMatch = content.match(/^(name|role|description|parentTools|tools):\s*(.+)$/m)
651
+ if (yamlMatch) {
652
+ config[yamlMatch[1]] = yamlMatch[2].trim()
653
+ }
654
+
655
+ // 如果没有找到配置,使用文件名作为 name
656
+ return config
657
+ }
658
+
659
+ /**
660
+ * 获取所有 subAgent 的基本信息列表
661
+ */
662
+ getAllSubAgents() {
663
+ return Array.from(this._subAgents.values());
664
+ }
665
+
666
+ /**
667
+ * 解析类似 YAML 的配置
668
+ */
669
+ _parseYamlLike(content) {
670
+ const result = {}
671
+ const lines = content.split('\n')
672
+
673
+ for (const line of lines) {
674
+ const match = line.match(/^(\w+):\s*(.+)$/)
675
+ if (match) {
676
+ const key = match[1]
677
+ let value = match[2].trim()
678
+
679
+ // 处理数组格式 [a, b, c] 或 [a b c]
680
+ if (value.startsWith('[') && value.endsWith(']')) {
681
+ value = value.slice(1, -1).split(/[,\s]+/).filter(Boolean)
682
+ }
683
+
684
+ result[key] = value
685
+ }
686
+ }
687
+
688
+ return result
689
+ }
690
+
691
+ /**
692
+ * 启动文件监控
693
+ */
694
+ _startFileWatcher() {
695
+ const agentsDir = this.config.agentsDir
696
+ if (!agentsDir || !fs.existsSync(agentsDir)) {
697
+ return
698
+ }
699
+
700
+ // 记录初始文件状态
701
+ this._updateFileStates()
702
+
703
+ // 使用 fs.watch 监控目录变化
704
+ this._fileWatcher = fs.watch(agentsDir, { recursive: false }, (eventType, filename) => {
705
+ if (filename && (filename.endsWith('.js') || filename.endsWith('.json') || filename.endsWith('.md'))) {
706
+ //console.log(`[SubAgentManager] Detected change in agents dir: ${eventType} - ${filename}`)
707
+
708
+ // 防抖:延迟处理,等文件操作完成
709
+ setTimeout(() => {
710
+ this._checkAndReload()
711
+ }, 500)
712
+ }
713
+ })
714
+
715
+ //console.log(`[SubAgentManager] Watching agents dir for changes: ${agentsDir}`)
716
+ }
717
+
718
+ /**
719
+ * 更新文件状态
720
+ */
721
+ _updateFileStates() {
722
+ const agentsDir = this.config.agentsDir
723
+ if (!agentsDir || !fs.existsSync(agentsDir)) {
724
+ return
725
+ }
726
+
727
+ this._lastFileStates.clear()
728
+ const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
729
+
730
+ for (const entry of entries) {
731
+ if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
732
+ const filePath = path.join(agentsDir, entry.name)
733
+ try {
734
+ const stat = fs.statSync(filePath)
735
+ this._lastFileStates.set(entry.name, {
736
+ mtime: stat.mtime.getTime(),
737
+ size: stat.size
738
+ })
739
+ } catch (err) {
740
+ // 忽略
741
+ }
742
+ }
743
+ }
744
+ }
745
+
746
+ /**
747
+ * 检查并重载(如果有变化)
748
+ */
749
+ _checkAndReload() {
750
+ const agentsDir = this.config.agentsDir
751
+ if (!agentsDir || !fs.existsSync(agentsDir)) {
752
+ return
753
+ }
754
+
755
+ const currentStates = new Map()
756
+ const entries = fs.readdirSync(agentsDir, { withFileTypes: true })
757
+ let hasChanges = false
758
+
759
+ // 检查当前文件
760
+ for (const entry of entries) {
761
+ if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.json') || entry.name.endsWith('.md'))) {
762
+ const filePath = path.join(agentsDir, entry.name)
763
+ try {
764
+ const stat = fs.statSync(filePath)
765
+ currentStates.set(entry.name, {
766
+ mtime: stat.mtime.getTime(),
767
+ size: stat.size
768
+ })
769
+
770
+ const lastState = this._lastFileStates.get(entry.name)
771
+ if (!lastState || lastState.mtime !== stat.mtime.getTime() || lastState.size !== stat.size) {
772
+ hasChanges = true
773
+ }
774
+ } catch (err) {
775
+ // 忽略
776
+ }
777
+ }
778
+ }
779
+
780
+ // 检查删除的文件
781
+ for (const [name] of this._lastFileStates) {
782
+ if (!currentStates.has(name)) {
783
+ hasChanges = true
784
+ break
785
+ }
786
+ }
787
+
788
+ if (hasChanges) {
789
+ //log.info(' File changes detected, reloading...')
790
+ this._updateFileStates()
791
+ this.reload(this._framework)
792
+ }
793
+ }
794
+
795
+ /**
796
+ * 获取子Agent
797
+ */
798
+ getSubAgent(name) {
799
+ const plugin = this._subAgents.get(name)
800
+ return plugin ? plugin.getAgent() : null
801
+ }
802
+
803
+ reload(framework) {
804
+ // 停止文件监控
805
+ if (this._fileWatcher) {
806
+ this._fileWatcher.close()
807
+ this._fileWatcher = null
808
+ }
809
+
810
+ // 销毁旧的子Agent
811
+ for (const plugin of this._subAgents.values()) {
812
+ plugin.uninstall(framework)
813
+ }
814
+ this._subAgents.clear()
815
+
816
+ // 清空从目录加载的配置,重新加载
817
+ this.agents = this.agents.filter(a => !a._fromDir)
818
+
819
+ // 刷新 SubAgentConfigManager(如果存在)
820
+ if (framework._subAgentConfigManager) {
821
+ framework._subAgentConfigManager.refresh()
822
+ }
823
+
824
+ // 重新创建
825
+ this.start(framework)
826
+ }
827
+
828
+ uninstall(framework) {
829
+ // 停止文件监控
830
+ if (this._fileWatcher) {
831
+ this._fileWatcher.close()
832
+ this._fileWatcher = null
833
+ }
834
+
835
+ for (const plugin of this._subAgents.values()) {
836
+ plugin.uninstall(framework)
837
+ }
838
+ this._subAgents.clear()
839
+ this._framework = null
840
+ }
841
+ }
842
+
843
+ module.exports = {
844
+ SubAgentPlugin,
845
+ SubAgentManagerPlugin
786
846
  }