foliko 1.1.93 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CLAUDE.md +56 -30
  3. package/REFACTORING_PLAN.md +645 -0
  4. package/docs/architecture.md +131 -0
  5. package/docs/migration.md +57 -0
  6. package/docs/public-api.md +138 -0
  7. package/docs/usage.md +385 -0
  8. package/examples/ambient-example.js +20 -137
  9. package/examples/basic.js +21 -48
  10. package/examples/bootstrap.js +16 -74
  11. package/examples/mcp-example.js +6 -29
  12. package/examples/skill-example.js +6 -19
  13. package/examples/workflow.js +8 -56
  14. package/package.json +8 -4
  15. package/plugins/README.md +49 -0
  16. package/plugins/{ambient-agent → ambient}/EventWatcher.js +1 -1
  17. package/plugins/{ambient-agent → ambient}/ExplorerLoop.js +3 -3
  18. package/plugins/{ambient-agent → ambient}/GoalManager.js +2 -2
  19. package/plugins/ambient/README.md +14 -0
  20. package/plugins/{ambient-agent → ambient}/Reflector.js +1 -1
  21. package/plugins/{ambient-agent → ambient}/StateStore.js +1 -1
  22. package/plugins/{ambient-agent → ambient}/index.js +2 -2
  23. package/plugins/{ai-plugin.js → core/ai/index.js} +14 -30
  24. package/plugins/{audit-plugin.js → core/audit/index.js} +3 -30
  25. package/plugins/{coordinator-plugin.js → core/coordinator/index.js} +3 -35
  26. package/plugins/core/default/bootstrap.js +224 -0
  27. package/plugins/core/default/config.js +222 -0
  28. package/plugins/core/default/index.js +58 -0
  29. package/plugins/core/mcp/index.js +1 -0
  30. package/plugins/{python-plugin-loader.js → core/python-loader/index.js} +7 -187
  31. package/plugins/{rules-plugin.js → core/rules/index.js} +121 -64
  32. package/plugins/{scheduler-plugin.js → core/scheduler/index.js} +12 -114
  33. package/plugins/{session-plugin.js → core/session/index.js} +9 -73
  34. package/{src/capabilities/skill-manager.js → plugins/core/skill-manager/index.js} +64 -18
  35. package/plugins/{storage-plugin.js → core/storage/index.js} +5 -29
  36. package/plugins/{subagent-plugin.js → core/sub-agent/index.js} +10 -171
  37. package/plugins/{think-plugin.js → core/think/index.js} +24 -91
  38. package/{src/capabilities/workflow-engine.js → plugins/core/workflow/index.js} +87 -85
  39. package/plugins/default-plugins.js +6 -720
  40. package/plugins/{data-splitter-plugin.js → executors/data-splitter/index.js} +9 -83
  41. package/plugins/{extension-executor-plugin.js → executors/extension/index.js} +13 -97
  42. package/plugins/{python-executor-plugin.js → executors/python/index.js} +6 -31
  43. package/plugins/{shell-executor-plugin.js → executors/shell/index.js} +2 -5
  44. package/plugins/install/README.md +9 -0
  45. package/plugins/{install-plugin.js → install/index.js} +3 -3
  46. package/plugins/{file-system-plugin.js → io/file-system/index.js} +34 -236
  47. package/plugins/{web-plugin.js → io/web/index.js} +11 -113
  48. package/plugins/memory/README.md +13 -0
  49. package/plugins/{memory-plugin.js → memory/index.js} +4 -18
  50. package/plugins/messaging/email/README.md +19 -0
  51. package/plugins/{email → messaging/email}/index.js +3 -3
  52. package/plugins/{feishu-plugin.js → messaging/feishu/index.js} +4 -4
  53. package/plugins/{qq-plugin.js → messaging/qq/index.js} +6 -17
  54. package/plugins/{telegram-plugin.js → messaging/telegram/index.js} +4 -4
  55. package/plugins/{weixin-plugin.js → messaging/weixin/index.js} +16 -16
  56. package/plugins/{plugin-manager-plugin.js → plugin-manager/index.js} +36 -180
  57. package/plugins/{tools-plugin.js → tools/index.js} +68 -116
  58. package/plugins/trading/README.md +15 -0
  59. package/plugins/{gate-trading.js → trading/index.js} +8 -8
  60. package/{examples → sandbox}/test-concurrent-chat.js +2 -2
  61. package/{examples → sandbox}/test-long-chat.js +2 -2
  62. package/{examples → sandbox}/test-session-chat.js +2 -2
  63. package/{examples → sandbox}/test-web-plugin.js +1 -1
  64. package/{examples → sandbox}/test-weixin-feishu.js +2 -2
  65. package/src/agent/base.js +56 -0
  66. package/src/{core/agent-chat.js → agent/chat.js} +11 -11
  67. package/src/{core/coordinator-manager.js → agent/coordinator.js} +3 -3
  68. package/src/agent/index.js +111 -0
  69. package/src/agent/main.js +337 -0
  70. package/src/agent/prompt.js +78 -0
  71. package/src/agent/sub.js +198 -0
  72. package/src/agent/worker.js +104 -0
  73. package/{cli/bin/foliko.js → src/cli/bin.js} +1 -1
  74. package/{cli/src → src/cli}/commands/chat.js +25 -21
  75. package/{cli/src → src/cli}/index.js +1 -0
  76. package/{cli/src → src/cli}/ui/chat-ui-old.js +40 -178
  77. package/{cli/src → src/cli}/ui/chat-ui.js +3 -3
  78. package/{cli/src → src/cli}/ui/components/footer-bar.js +1 -1
  79. package/src/common/errors.js +402 -0
  80. package/src/{utils → common}/logger.js +33 -0
  81. package/src/{utils/chat-queue.js → common/queue.js} +2 -2
  82. package/src/config/plugin-config.js +50 -0
  83. package/src/context/agent.js +32 -0
  84. package/src/context/compaction-prompts.js +170 -0
  85. package/src/context/compaction-utils.js +191 -0
  86. package/src/context/compressor.js +413 -0
  87. package/src/context/index.js +9 -0
  88. package/src/{core/context-manager.js → context/manager.js} +1 -1
  89. package/src/context/request.js +50 -0
  90. package/src/context/session.js +33 -0
  91. package/src/context/storage.js +30 -0
  92. package/src/executors/mcp-client.js +153 -0
  93. package/src/executors/mcp-desc.js +236 -0
  94. package/src/executors/mcp-executor.js +91 -956
  95. package/src/{core → framework}/command-registry.js +1 -1
  96. package/src/framework/framework.js +300 -0
  97. package/src/framework/index.js +18 -0
  98. package/src/framework/lifecycle.js +203 -0
  99. package/src/framework/loader.js +78 -0
  100. package/src/framework/registry.js +86 -0
  101. package/src/{core/ui-extension-context.js → framework/ui-extension.js} +1 -1
  102. package/src/index.js +130 -15
  103. package/src/llm/index.js +26 -0
  104. package/src/llm/provider.js +212 -0
  105. package/src/llm/registry.js +11 -0
  106. package/src/{core/token-counter.js → llm/tokens.js} +4 -37
  107. package/src/{core/plugin-base.js → plugin/base.js} +10 -136
  108. package/src/plugin/index.js +14 -0
  109. package/src/plugin/loader.js +101 -0
  110. package/src/plugin/manager.js +484 -0
  111. package/src/{core → session}/branch-summary-auto.js +2 -2
  112. package/src/{core/chat-session.js → session/chat.js} +2 -2
  113. package/src/session/index.js +7 -0
  114. package/src/{core/session-manager.js → session/session.js} +2 -2
  115. package/src/session/ttl.js +92 -0
  116. package/src/{core/jsonl-storage.js → storage/jsonl.js} +1 -1
  117. package/src/tool/executor.js +85 -0
  118. package/src/tool/index.js +15 -0
  119. package/src/tool/registry.js +143 -0
  120. package/src/{core/tool-router.js → tool/router.js} +17 -124
  121. package/src/tool/schema.js +108 -0
  122. package/src/utils/data-splitter.js +1 -1
  123. package/src/utils/download.js +1 -1
  124. package/src/utils/index.js +6 -6
  125. package/src/utils/message-validator.js +1 -1
  126. package/tests/core/context-storage.test.js +46 -0
  127. package/tests/core/llm.test.js +54 -0
  128. package/tests/core/plugin.test.js +42 -0
  129. package/tests/core/tool.test.js +60 -0
  130. package/tests/setup.js +10 -0
  131. package/tests/smoke.test.js +58 -0
  132. package/vitest.config.js +9 -0
  133. package/cli/src/daemon.js +0 -149
  134. package/docs/CONTEXT_DESIGN.md +0 -1596
  135. package/docs/ai-sdk-optimization.md +0 -655
  136. package/docs/features.md +0 -120
  137. package/docs/qq-bot.md +0 -976
  138. package/docs/quick-reference.md +0 -160
  139. package/docs/user-manual.md +0 -1391
  140. package/images/geometric_shapes.jpg +0 -0
  141. package/images/sunset_mountain_lake.jpg +0 -0
  142. package/skills/poster-guide/SKILL.md +0 -792
  143. package/src/capabilities/index.js +0 -11
  144. package/src/core/agent.js +0 -808
  145. package/src/core/context-compressor.js +0 -959
  146. package/src/core/enhanced-context-compressor.js +0 -210
  147. package/src/core/framework.js +0 -1422
  148. package/src/core/index.js +0 -30
  149. package/src/core/plugin-manager.js +0 -961
  150. package/src/core/provider-registry.js +0 -159
  151. package/src/core/provider.js +0 -156
  152. package/src/core/request-context.js +0 -98
  153. package/src/core/subagent.js +0 -442
  154. package/src/core/system-prompt-builder.js +0 -120
  155. package/src/core/tool-executor.js +0 -202
  156. package/src/core/tool-registry.js +0 -517
  157. package/src/core/worker-agent.js +0 -192
  158. package/src/executors/executor-base.js +0 -58
  159. package/src/utils/error-boundary.js +0 -363
  160. package/src/utils/error.js +0 -374
  161. package/system.md +0 -1645
  162. package/website_v2/README.md +0 -57
  163. package/website_v2/SPEC.md +0 -1
  164. package/website_v2/docs/api.html +0 -128
  165. package/website_v2/docs/configuration.html +0 -147
  166. package/website_v2/docs/plugin-development.html +0 -129
  167. package/website_v2/docs/project-structure.html +0 -89
  168. package/website_v2/docs/skill-development.html +0 -85
  169. package/website_v2/index.html +0 -489
  170. package/website_v2/scripts/main.js +0 -93
  171. package/website_v2/styles/animations.css +0 -8
  172. package/website_v2/styles/docs.css +0 -83
  173. package/website_v2/styles/main.css +0 -417
  174. package/xhs_auth.json +0 -268
  175. package//346/265/267/346/212/245/346/217/222/344/273/266.md +0 -621
  176. /package/plugins/{ambient-agent → ambient}/constants.js +0 -0
  177. /package/plugins/{email → messaging/email}/constants.js +0 -0
  178. /package/plugins/{email → messaging/email}/handlers.js +0 -0
  179. /package/plugins/{email → messaging/email}/monitor.js +0 -0
  180. /package/plugins/{email → messaging/email}/parser.js +0 -0
  181. /package/plugins/{email → messaging/email}/reply.js +0 -0
  182. /package/plugins/{email → messaging/email}/utils.js +0 -0
  183. /package/{examples → sandbox}/test-chat.js +0 -0
  184. /package/{examples → sandbox}/test-mcp.js +0 -0
  185. /package/{examples → sandbox}/test-reload.js +0 -0
  186. /package/{examples → sandbox}/test-telegram.js +0 -0
  187. /package/{examples → sandbox}/test-tg-bot.js +0 -0
  188. /package/{examples → sandbox}/test-tg-simple.js +0 -0
  189. /package/{examples → sandbox}/test-tg.js +0 -0
  190. /package/{examples → sandbox}/test-think.js +0 -0
  191. /package/src/{core/sub-agent-config.js → agent/sub-config.js} +0 -0
  192. /package/{cli/src → src/cli}/commands/daemon.js +0 -0
  193. /package/{cli/src → src/cli}/commands/list.js +0 -0
  194. /package/{cli/src → src/cli}/commands/plugin.js +0 -0
  195. /package/{cli/src → src/cli}/ui/components/agent-mention-provider.js +0 -0
  196. /package/{cli/src → src/cli}/ui/components/chained-autocomplete-provider.js +0 -0
  197. /package/{cli/src → src/cli}/ui/components/message-bubble.js +0 -0
  198. /package/{cli/src → src/cli}/ui/components/status-bar.js +0 -0
  199. /package/{cli/src → src/cli}/utils/ansi.js +0 -0
  200. /package/{cli/src → src/cli}/utils/config.js +0 -0
  201. /package/{cli/src → src/cli}/utils/markdown.js +0 -0
  202. /package/{cli/src → src/cli}/utils/plugin-config.js +0 -0
  203. /package/{cli/src → src/cli}/utils/render-diff.js +0 -0
  204. /package/src/{utils/circuit-breaker.js → common/circuit.js} +0 -0
  205. /package/src/{core → common}/constants.js +0 -0
  206. /package/src/{utils/edit-diff.js → common/diff.js} +0 -0
  207. /package/src/{utils/event-emitter.js → common/events.js} +0 -0
  208. /package/src/{utils → common}/id.js +0 -0
  209. /package/src/{utils → common}/retry.js +0 -0
  210. /package/src/{core/notification-manager.js → notification/manager.js} +0 -0
  211. /package/src/{core/session-entry.js → session/entry.js} +0 -0
  212. /package/src/{core/storage-manager.js → storage/manager.js} +0 -0
@@ -3,8 +3,8 @@
3
3
  * 支持 LLM 自我唤醒、自动反思、持续思考
4
4
  */
5
5
 
6
- const { Plugin } = require('../src/core/plugin-base')
7
- const { logger } = require('../src/utils/logger')
6
+ const { Plugin } = require('../../../src/plugin/base')
7
+ const { logger } = require('../../../src/common/logger')
8
8
  const log = logger.child('Think')
9
9
  const { z } = require('zod')
10
10
 
@@ -14,27 +14,27 @@ class ThinkPlugin extends Plugin {
14
14
  this.name = 'think'
15
15
  this.version = '1.0.0'
16
16
  this.description = '主动思考插件,支持 LLM 自我唤醒和持续思考'
17
- this.priority = 5 // 高优先级,早期加载
17
+ this.priority = 5
18
18
 
19
19
  this.config = {
20
- autoReflect: config.autoReflect === true, // 默认关闭自动反思
21
- reflectDelay: config.reflectDelay || 2000, // 反思延迟(ms)
22
- maxReflectDepth: config.maxReflectDepth || 3, // 最大反思深度
23
- enableContinuous: config.enableContinuous || false // 是否启用持续思考
20
+ autoReflect: config.autoReflect === true,
21
+ reflectDelay: config.reflectDelay || 2000,
22
+ maxReflectDepth: config.maxReflectDepth || 3,
23
+ enableContinuous: config.enableContinuous || false
24
24
  }
25
- this.tools = {} // 存储注册的工具函数
25
+ this.tools = {}
26
26
  this._framework = null
27
- this._thoughts = [] // 思考记录
28
- this._thinkAgent = null // 缓存的思考子 agent
29
- this._reflectionChain = [] // 反思链
27
+ this._thoughts = []
28
+ this._thinkAgent = null
29
+ this._reflectionChain = []
30
30
  this._continuousMode = false
31
31
  this._continuousTimer = null
32
32
  this._continuousTopic = null
33
- this._continuousMessages = [] // 持续思考的上下文消息
34
- this._continuousRounds = 0 // 持续思考轮次计数
35
- this._lastThinkResultHash = null // 上次思考结果 hash(用于检测重复)
36
- this._consecutiveSimilarRounds = 0 // 连续相似轮次计数
37
- this._maxContinuousRounds = 10 // 默认最大轮次
33
+ this._continuousMessages = []
34
+ this._continuousRounds = 0
35
+ this._lastThinkResultHash = null
36
+ this._consecutiveSimilarRounds = 0
37
+ this._maxContinuousRounds = 10
38
38
  this._pendingReflection = null
39
39
  }
40
40
 
@@ -44,9 +44,6 @@ class ThinkPlugin extends Plugin {
44
44
  }
45
45
 
46
46
  start(framework) {
47
- // 注册思考工具 - 这些工具可以让主 agent 的 LLM 调用
48
- // think 支持工具执行循环,LLM 可以让它完成需要调用工具的任务
49
-
50
47
  framework.registerTool({
51
48
  name: 'think_now',
52
49
  description: '触发深度思考,支持调用工具分析项目代码。当需要分析、优化、修改代码或文件时使用此工具。',
@@ -101,13 +98,9 @@ class ThinkPlugin extends Plugin {
101
98
  return this
102
99
  }
103
100
 
104
- /**
105
- * 创建思考用的 Subagent
106
- */
107
101
  _createThinkSubagent() {
108
102
  const aiPlugin = this._framework.pluginManager?.get('ai');
109
103
  const aiConfig = aiPlugin ? aiPlugin.getConfig() : {};
110
- // log.info(`[Think] createSubAgent AI config: provider=${aiConfig.provider}, model=${aiConfig.model}, hasKey=${!!aiConfig.apiKey}`);
111
104
  return this._framework.createSubAgent({
112
105
  name: 'think',
113
106
  role: '思考助手',
@@ -126,26 +119,14 @@ class ThinkPlugin extends Plugin {
126
119
  })
127
120
  }
128
121
 
129
- /**
130
- * 触发主动思考
131
- * @param {Object} args - 参数
132
- * @param {string} args.topic - 思考主题
133
- * @param {string} args.mode - 思考模式
134
- * @param {number} args.depth - 思考深度
135
- * @param {Object} args.agent - 外部 agent
136
- * @param {Array} args.messages - 可选,上下文消息数组用于持续对话
137
- */
138
122
  async _triggerThinking(args) {
139
123
  const mode = args.mode || 'reflect'
140
124
  const depth = Math.min(args.depth || 2, 5)
141
125
  const topic = args.topic || '刚才的对话还有什么可以改进或补充的地方?'
142
- // 支持外部传入 agent
143
126
  const externalAgent = args.agent
144
- // 支持传入上下文消息
145
127
  const contextMessages = args.messages
146
128
 
147
129
  try {
148
- // 检查 AI 配置
149
130
  const aiPlugin = this._framework.pluginManager?.get('ai')
150
131
  if (!aiPlugin) {
151
132
  this._emitNotification('error', '🧠 思考失败', 'AI 未配置')
@@ -157,18 +138,13 @@ class ThinkPlugin extends Plugin {
157
138
 
158
139
  const reflectPrompt = this._buildReflectPrompt(mode, depth, topic)
159
140
 
160
- // 优先使用外部传入的 agent,否则使用缓存的 think agent
161
141
  const thinkAgent = externalAgent || this._thinkAgent || (this._thinkAgent = this._createThinkSubagent())
162
- // log.info(`[Think] thinkAgent apiKey: ${thinkAgent.apiKey ? thinkAgent.apiKey.substring(0,8) + '...' : 'null'}, provider: ${thinkAgent.provider}, model: ${thinkAgent.model}`)
163
142
 
164
143
  let result
165
144
  if (contextMessages && contextMessages.length > 0) {
166
- // 持续对话模式:传入上下文消息
167
145
  const messages = [...contextMessages, { role: 'user', content: reflectPrompt }]
168
- // log.info(`[Think] round with context: contextLen=${contextMessages.length}, totalMsgs=${messages.length}`);
169
146
  result = await thinkAgent.chat(messages)
170
147
  } else {
171
- // 普通模式:新对话
172
148
  result = await thinkAgent.chat(reflectPrompt)
173
149
  }
174
150
 
@@ -182,18 +158,15 @@ class ThinkPlugin extends Plugin {
182
158
  timestamp: new Date()
183
159
  }
184
160
 
185
- // log.info(`[Think] result.messages length: ${result.messages ? result.messages.length : 'undefined/null'}, success: ${result.success}, msgLen: ${(result.message || '').length}`);
186
161
  this._thoughts.push(thought)
187
162
  if (this._thoughts.length > 100) {
188
163
  this._thoughts = this._thoughts.slice(-100)
189
164
  }
190
165
 
191
- // 返回消息数组(用于持续对话)
192
166
  if (contextMessages) {
193
167
  thought.messages = [...contextMessages, { role: 'user', content: reflectPrompt }, { role: 'assistant', content: result.message }]
194
168
  }
195
169
 
196
- // 触发思考完成事件(使用文档规定的字段结构)
197
170
  if (this._framework) {
198
171
  this._framework.emit('think:thought_completed', {
199
172
  topic: thought.topic,
@@ -201,7 +174,6 @@ class ThinkPlugin extends Plugin {
201
174
  depth: thought.depth
202
175
  })
203
176
 
204
- // 发送通知
205
177
  const level = mode === 'brainstorm' ? 'success' : 'info'
206
178
  this._emitNotification(level, '🧠 思考完成', thought.result)
207
179
  }
@@ -222,9 +194,6 @@ class ThinkPlugin extends Plugin {
222
194
  }
223
195
  }
224
196
 
225
- /**
226
- * 发送通知
227
- */
228
197
  _emitNotification(level, title, message) {
229
198
  if (!this._framework) return
230
199
  this._framework.emit('notification', {
@@ -236,9 +205,6 @@ class ThinkPlugin extends Plugin {
236
205
  })
237
206
  }
238
207
 
239
- /**
240
- * 构建反思提示
241
- */
242
208
  _buildReflectPrompt(mode, depth, topic) {
243
209
  const depthDesc = {
244
210
  1: '快速检视',
@@ -284,20 +250,15 @@ ${topic || '接下来的行动'}
284
250
  return modePrompts[mode] || modePrompts.reflect
285
251
  }
286
252
 
287
- /**
288
- * 自动反思(响应完成后)
289
- */
290
253
  async _autoReflect(data) {
291
254
  if (!this._framework) return
292
255
 
293
256
  try {
294
- // 检查是否需要反思(避免短时间重复反思)
295
257
  const lastThought = this._thoughts[this._thoughts.length - 1]
296
258
  if (lastThought && Date.now() - lastThought.timestamp.getTime() < 10000) {
297
- return // 10秒内不重复反思
259
+ return
298
260
  }
299
261
 
300
- // 构建轻量级反思
301
262
  const reflectPrompt = `作为助手,请快速检视刚才的回答是否:
302
263
  1. 完整回答了用户的问题
303
264
  2. 表达清晰易懂
@@ -305,7 +266,6 @@ ${topic || '接下来的行动'}
305
266
 
306
267
  如果发现不足,请直接补充。如果没问题,请简短回复"检查完毕,无需补充"。`
307
268
 
308
- // 使用轻量 Subagent 静默思考,不打断用户
309
269
  const thinkAgent = this._createThinkSubagent()
310
270
  const result = await thinkAgent.chat(reflectPrompt)
311
271
 
@@ -320,7 +280,6 @@ ${topic || '接下来的行动'}
320
280
 
321
281
  this._thoughts.push(thought)
322
282
 
323
- // 如果反思有重要补充,触发事件通知
324
283
  if (result.message?.includes('补充') && !result.message?.includes('无需补充')) {
325
284
  this._framework.emit('think:reflection_needs_attention', {
326
285
  thought,
@@ -332,9 +291,6 @@ ${topic || '接下来的行动'}
332
291
  }
333
292
  }
334
293
 
335
- /**
336
- * 启动持续思考模式
337
- */
338
294
  async _startContinuousThinking(args) {
339
295
  if (this._continuousMode) {
340
296
  this._emitNotification('warning', '⚠️ 持续思考', '持续思考已在运行中')
@@ -343,16 +299,15 @@ ${topic || '接下来的行动'}
343
299
 
344
300
  const interval = args.interval || 30000
345
301
  const topic = args.topic || '基于最近的对话,还有什么值得深入思考的方向?'
346
- const maxRounds = args.maxRounds || 10 // 默认最多10轮
302
+ const maxRounds = args.maxRounds || 10
347
303
 
348
304
  this._continuousMode = true
349
305
  this._continuousTopic = topic
350
- this._continuousMessages = [] // 初始化上下文消息
351
- this._continuousRounds = 0 // 当前轮次计数
352
- this._lastThinkResultHash = null // 上次思考结果的 hash,用于检测重复
353
- this._consecutiveSimilarRounds = 0 // 连续相似轮次计数
306
+ this._continuousMessages = []
307
+ this._continuousRounds = 0
308
+ this._lastThinkResultHash = null
309
+ this._consecutiveSimilarRounds = 0
354
310
  this._maxContinuousRounds = maxRounds
355
- // 注意:不再需要捕获 sessionId,因为总结不加到会话
356
311
 
357
312
  const runThink = async () => {
358
313
  if (!this._continuousMode) return
@@ -367,18 +322,14 @@ ${topic || '接下来的行动'}
367
322
 
368
323
  this._continuousRounds++
369
324
 
370
- // 更新上下文消息(用于下次思考)
371
325
  if (result.messages) {
372
326
  this._continuousMessages = result.messages
373
- // 限制上下文长度,最多保留 10 条消息
374
327
  if (this._continuousMessages.length > 10) {
375
328
  this._continuousMessages = this._continuousMessages.slice(-10)
376
329
  }
377
330
  }
378
331
 
379
- // 自然停止检测:结果相似度判断 + LLM 主动确认无新论点(第一轮不触发判断)
380
332
  const currentResult = (result.thought?.result || '').trim()
381
- // 第一轮不判断无新论点(还没有内容可供对比),后续轮次才判断
382
333
  const noNewPoints = this._continuousRounds > 1 && currentResult.includes('【无新增论点,思考已充分】')
383
334
  const currentHash = this._hashString(currentResult)
384
335
  if (this._lastThinkResultHash !== null && currentHash === this._lastThinkResultHash) {
@@ -388,7 +339,6 @@ ${topic || '接下来的行动'}
388
339
  }
389
340
  this._lastThinkResultHash = currentHash
390
341
 
391
- // 满足自然停止条件:LLM 主动确认无新论点 或 连续3轮相似 或 达到最大轮次
392
342
  const shouldStopNaturally =
393
343
  noNewPoints ||
394
344
  this._consecutiveSimilarRounds >= 3 ||
@@ -401,7 +351,6 @@ ${topic || '接下来的行动'}
401
351
  return
402
352
  }
403
353
 
404
- // 触发下一轮
405
354
  if (this._continuousMode) {
406
355
  this._continuousTimer = setTimeout(runThink, interval)
407
356
  }
@@ -411,7 +360,6 @@ ${topic || '接下来的行动'}
411
360
  }
412
361
  }
413
362
 
414
- // 立即执行一次
415
363
  await runThink()
416
364
 
417
365
  this._emitNotification('success', '✅ 持续思考已启动', `间隔: ${interval}ms`)
@@ -419,12 +367,9 @@ ${topic || '接下来的行动'}
419
367
  return {
420
368
  success: true,
421
369
  data: `【持续思考已启动】\n间隔: ${interval}ms\n主题: ${topic}\n\nLLM 将定期自动思考并在有新想法时通知你。`
422
- }
370
+ }
423
371
  }
424
372
 
425
- /**
426
- * 停止持续思考模式
427
- */
428
373
  _stopContinuousThinking() {
429
374
  const rounds = this._continuousRounds
430
375
  this._continuousMode = false
@@ -432,7 +377,7 @@ ${topic || '接下来的行动'}
432
377
  clearTimeout(this._continuousTimer)
433
378
  this._continuousTimer = null
434
379
  }
435
- this._continuousMessages = [] // 清空上下文
380
+ this._continuousMessages = []
436
381
  this._continuousTopic = null
437
382
  this._continuousRounds = 0
438
383
  this._lastThinkResultHash = null
@@ -444,16 +389,11 @@ ${topic || '接下来的行动'}
444
389
  }
445
390
  }
446
391
 
447
- /**
448
- * 获取当前活跃的 Agent
449
- */
450
392
  _getActiveAgent() {
451
- // 优先使用主 Agent
452
393
  if (this._framework._mainAgent) {
453
394
  return this._framework._mainAgent
454
395
  }
455
396
 
456
- // 否则找一个空闲的 Agent
457
397
  if (this._framework._agents && this._framework._agents.length > 0) {
458
398
  for (let i = this._framework._agents.length - 1; i >= 0; i--) {
459
399
  const agent = this._framework._agents[i]
@@ -465,19 +405,12 @@ ${topic || '接下来的行动'}
465
405
  return null
466
406
  }
467
407
 
468
- /**
469
- * 获取待处理的反思通知
470
- */
471
408
  getPendingThoughts() {
472
409
  return this._thoughts.slice(-10).reverse()
473
410
  }
474
411
 
475
- /**
476
- * 字符串 hash(用于判断思考结果是否重复)
477
- */
478
412
  _hashString(str) {
479
413
  if (!str || str.length === 0) return ''
480
- // 简化为取前64字符的 hashcode
481
414
  let hash = 0
482
415
  const s = str.substring(0, 64)
483
416
  for (let i = 0; i < s.length; i++) {
@@ -2,15 +2,16 @@
2
2
  * WorkflowEngine 工作流引擎
3
3
  * 支持结构化工作流定义和执行
4
4
  */
5
- const { EventEmitter } = require('../utils/event-emitter');
6
- const { Plugin } = require('../core/plugin-base');
7
- const { logger } = require('../utils/logger');
5
+ const { EventEmitter } = require('../../../src/common/events');
6
+ const { Plugin } = require('../../../src/plugin/base');
7
+ const { logger } = require('../../../src/common/logger');
8
8
  const log = logger.child('Workflow');
9
9
  const { z } = require('zod');
10
- const { runScriptSafely, evaluateInSandbox, runWorkflowFileSafely, runWorkflowSafely } = require('../utils/sandbox');
10
+ const { runScriptSafely, evaluateInSandbox, runWorkflowFileSafely, runWorkflowSafely } = require('../../../src/utils/sandbox');
11
11
  const fs = require('fs');
12
12
  const crypto = require('crypto');
13
13
  const path = require('path');
14
+ const os = require('os');
14
15
  /**
15
16
  * 工作流步骤类型
16
17
  */
@@ -821,6 +822,7 @@ class WorkflowPlugin extends Plugin {
821
822
  this._framework = null;
822
823
  this._engine = null;
823
824
  this._workflowsDir = config.workflowsDir || '.foliko/workflows';
825
+ this._homeWorkflowsDir = path.join(os.homedir(), '.foliko', 'workflows');
824
826
  this._workflows = new Map();
825
827
  this._workflowTools = new Map();
826
828
  }
@@ -875,6 +877,29 @@ class WorkflowPlugin extends Plugin {
875
877
  };
876
878
  },
877
879
  });
880
+
881
+ // 注册列出工作流的工具
882
+ framework.registerTool({
883
+ name: 'listWorkflows',
884
+ description: '列出所有已加载的工作流及其描述信息',
885
+ inputSchema: z.object({}),
886
+ execute: async () => {
887
+ const workflows = [];
888
+ for (const [name, workflow] of this._workflows) {
889
+ workflows.push({
890
+ name,
891
+ description: workflow.description || '',
892
+ stepCount: workflow.steps?.length || 0,
893
+ type: workflow.type || 'sequential',
894
+ });
895
+ }
896
+ return {
897
+ success: true,
898
+ data: workflows,
899
+ metadata: { total: this._workflows.size },
900
+ };
901
+ },
902
+ });
878
903
  return this;
879
904
  }
880
905
  /**
@@ -882,44 +907,49 @@ class WorkflowPlugin extends Plugin {
882
907
  */
883
908
  _loadWorkflows() {
884
909
  const cwd = this._framework?.getCwd?.() ?? process.cwd();
885
- const dir = path.resolve(cwd, this._workflowsDir);
886
- if (!fs.existsSync(dir)) {
887
- fs.mkdirSync(dir, { recursive: true });
888
- // log.info(` Created workflows directory: ${dir}`);
889
- return;
890
- }
891
- try {
892
- const files = fs.readdirSync(dir);
893
- for (const file of files) {
894
- if (!file.endsWith('.json') && !file.endsWith('.js')) continue;
895
- const filePath = path.join(dir, file);
896
- const workflowName = path.basename(file, path.extname(file));
897
- // 跳过已存在的工作流
898
- if (this._workflows.has(workflowName)) continue;
899
- try {
900
- const content = fs.readFileSync(filePath, 'utf-8');
901
- let workflowDef;
902
- if (file.endsWith('.js')) {
903
- // 执行 JS 文件获取工作流定义
904
- // 使用沙箱加载工作流文件,防止恶意代码执行
905
- workflowDef = runWorkflowFileSafely(content, { timeout: 10000 });
906
- if (typeof workflowDef === 'function') {
907
- workflowDef = workflowDef(this._engine || {});
910
+ const dirs = [
911
+ this._homeWorkflowsDir, // ~/.foliko/workflows(优先)
912
+ path.resolve(cwd, this._workflowsDir), // 项目级
913
+ ];
914
+
915
+ for (const dir of dirs) {
916
+ if (!fs.existsSync(dir)) {
917
+ // 只创建项目级目录
918
+ if (dir === path.resolve(cwd, this._workflowsDir)) {
919
+ fs.mkdirSync(dir, { recursive: true });
920
+ }
921
+ continue;
922
+ }
923
+ try {
924
+ const files = fs.readdirSync(dir);
925
+ for (const file of files) {
926
+ if (!file.endsWith('.json') && !file.endsWith('.js')) continue;
927
+ const filePath = path.join(dir, file);
928
+ const workflowName = path.basename(file, path.extname(file));
929
+ // 跳过已存在的工作流(先加载的优先)
930
+ if (this._workflows.has(workflowName)) continue;
931
+ try {
932
+ const content = fs.readFileSync(filePath, 'utf-8');
933
+ let workflowDef;
934
+ if (file.endsWith('.js')) {
935
+ workflowDef = runWorkflowFileSafely(content, { timeout: 10000 });
936
+ if (typeof workflowDef === 'function') {
937
+ workflowDef = workflowDef(this._engine || {});
938
+ }
939
+ workflowDef = workflowDef.default || workflowDef;
940
+ } else {
941
+ workflowDef = JSON.parse(content);
908
942
  }
909
- workflowDef = workflowDef.default || workflowDef;
910
- } else {
911
- workflowDef = JSON.parse(content);
912
- }
913
- if (workflowDef && workflowDef.steps) {
914
- this._workflows.set(workflowName, workflowDef);
915
- //// log.info(` Loaded: ${workflowName}`)
943
+ if (workflowDef && workflowDef.steps) {
944
+ this._workflows.set(workflowName, workflowDef);
945
+ }
946
+ } catch (err) {
947
+ log.error(` Failed to load ${file}:`, err.message);
916
948
  }
917
- } catch (err) {
918
- log.error(` Failed to load ${file}:`, err.message);
919
949
  }
950
+ } catch (err) {
951
+ log.error(` Failed to read workflows directory ${dir}:`, err.message);
920
952
  }
921
- } catch (err) {
922
- log.error(' Failed to read workflows directory:', err.message);
923
953
  }
924
954
  }
925
955
  /**
@@ -954,56 +984,23 @@ class WorkflowPlugin extends Plugin {
954
984
  * 重载工作流
955
985
  */
956
986
  reload(framework) {
957
- // 清除模块缓存,确保重新加载最新代码
958
- const modulePath = require.resolve('./src/capabilities/workflow-engine');
959
- if (require.cache[modulePath]) {
960
- delete require.cache[modulePath];
961
- }
962
- // log.info(' Reloading...');
987
+ // 清除当前模块缓存,确保重新加载最新代码
988
+ delete require.cache[__filename];
963
989
  this._framework = framework;
990
+ const fresh = require(__filename);
964
991
  // 重新创建 engine(确保使用最新代码)
965
- this._engine = new (require('./src/capabilities/workflow-engine').WorkflowEngine)(framework);
992
+ this._engine = new fresh.WorkflowEngine(framework);
966
993
  // 注册内置步骤类型
967
- this._engine.registerStepType(
968
- require('./src/capabilities/workflow-engine').StepType.SCRIPT,
969
- require('./src/capabilities/workflow-engine').ScriptStep
970
- );
971
- this._engine.registerStepType(
972
- require('./src/capabilities/workflow-engine').StepType.TOOL,
973
- require('./src/capabilities/workflow-engine').ToolStep
974
- );
975
- this._engine.registerStepType(
976
- require('./src/capabilities/workflow-engine').StepType.CONDITION,
977
- require('./src/capabilities/workflow-engine').ConditionStep
978
- );
979
- this._engine.registerStepType(
980
- require('./src/capabilities/workflow-engine').StepType.SWITCH,
981
- require('./src/capabilities/workflow-engine').SwitchStep
982
- );
983
- this._engine.registerStepType(
984
- require('./src/capabilities/workflow-engine').StepType.TRY,
985
- require('./src/capabilities/workflow-engine').TryStep
986
- );
987
- this._engine.registerStepType(
988
- require('./src/capabilities/workflow-engine').StepType.PARALLEL,
989
- require('./src/capabilities/workflow-engine').ParallelStep
990
- );
991
- this._engine.registerStepType(
992
- require('./src/capabilities/workflow-engine').StepType.SEQUENTIAL,
993
- require('./src/capabilities/workflow-engine').SequentialStep
994
- );
995
- this._engine.registerStepType(
996
- require('./src/capabilities/workflow-engine').StepType.LOOP,
997
- require('./src/capabilities/workflow-engine').LoopStep
998
- );
999
- this._engine.registerStepType(
1000
- require('./src/capabilities/workflow-engine').StepType.DELAY,
1001
- require('./src/capabilities/workflow-engine').DelayStep
1002
- );
1003
- this._engine.registerStepType(
1004
- require('./src/capabilities/workflow-engine').StepType.WORKFLOW,
1005
- require('./src/capabilities/workflow-engine').NestedWorkflowStep
1006
- );
994
+ this._engine.registerStepType(fresh.StepType.SCRIPT, fresh.ScriptStep);
995
+ this._engine.registerStepType(fresh.StepType.TOOL, fresh.ToolStep);
996
+ this._engine.registerStepType(fresh.StepType.CONDITION, fresh.ConditionStep);
997
+ this._engine.registerStepType(fresh.StepType.SWITCH, fresh.SwitchStep);
998
+ this._engine.registerStepType(fresh.StepType.TRY, fresh.TryStep);
999
+ this._engine.registerStepType(fresh.StepType.PARALLEL, fresh.ParallelStep);
1000
+ this._engine.registerStepType(fresh.StepType.SEQUENTIAL, fresh.SequentialStep);
1001
+ this._engine.registerStepType(fresh.StepType.LOOP, fresh.LoopStep);
1002
+ this._engine.registerStepType(fresh.StepType.DELAY, fresh.DelayStep);
1003
+ this._engine.registerStepType(fresh.StepType.WORKFLOW, fresh.NestedWorkflowStep);
1007
1004
  // 清除已注册的工具
1008
1005
  for (const toolName of this._workflowTools.values()) {
1009
1006
  // 工具注销需要框架支持,这里只清理内部状态
@@ -1015,6 +1012,11 @@ class WorkflowPlugin extends Plugin {
1015
1012
  this._registerWorkflowTools();
1016
1013
  // log.info(` Reloaded. Total workflows: ${this._workflows.size}`);
1017
1014
  }
1015
+
1016
+ async onCwdChanged(oldCwd, newCwd, framework) {
1017
+ this._workflowTools.clear();
1018
+ this._workflows.clear();
1019
+ }
1018
1020
  /**
1019
1021
  * 执行工作流
1020
1022
  */