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.
- package/.claude/settings.local.json +2 -1
- package/CLAUDE.md +56 -30
- package/REFACTORING_PLAN.md +645 -0
- package/docs/architecture.md +131 -0
- package/docs/migration.md +57 -0
- package/docs/public-api.md +138 -0
- package/docs/usage.md +385 -0
- package/examples/ambient-example.js +20 -137
- package/examples/basic.js +21 -48
- package/examples/bootstrap.js +16 -74
- package/examples/mcp-example.js +6 -29
- package/examples/skill-example.js +6 -19
- package/examples/workflow.js +8 -56
- package/package.json +8 -4
- package/plugins/README.md +49 -0
- package/plugins/{ambient-agent → ambient}/EventWatcher.js +1 -1
- package/plugins/{ambient-agent → ambient}/ExplorerLoop.js +3 -3
- package/plugins/{ambient-agent → ambient}/GoalManager.js +2 -2
- package/plugins/ambient/README.md +14 -0
- package/plugins/{ambient-agent → ambient}/Reflector.js +1 -1
- package/plugins/{ambient-agent → ambient}/StateStore.js +1 -1
- package/plugins/{ambient-agent → ambient}/index.js +2 -2
- package/plugins/{ai-plugin.js → core/ai/index.js} +14 -30
- package/plugins/{audit-plugin.js → core/audit/index.js} +3 -30
- package/plugins/{coordinator-plugin.js → core/coordinator/index.js} +3 -35
- package/plugins/core/default/bootstrap.js +224 -0
- package/plugins/core/default/config.js +222 -0
- package/plugins/core/default/index.js +58 -0
- package/plugins/core/mcp/index.js +1 -0
- package/plugins/{python-plugin-loader.js → core/python-loader/index.js} +7 -187
- package/plugins/{rules-plugin.js → core/rules/index.js} +121 -64
- package/plugins/{scheduler-plugin.js → core/scheduler/index.js} +12 -114
- package/plugins/{session-plugin.js → core/session/index.js} +9 -73
- package/{src/capabilities/skill-manager.js → plugins/core/skill-manager/index.js} +64 -18
- package/plugins/{storage-plugin.js → core/storage/index.js} +5 -29
- package/plugins/{subagent-plugin.js → core/sub-agent/index.js} +10 -171
- package/plugins/{think-plugin.js → core/think/index.js} +24 -91
- package/{src/capabilities/workflow-engine.js → plugins/core/workflow/index.js} +87 -85
- package/plugins/default-plugins.js +6 -720
- package/plugins/{data-splitter-plugin.js → executors/data-splitter/index.js} +9 -83
- package/plugins/{extension-executor-plugin.js → executors/extension/index.js} +13 -97
- package/plugins/{python-executor-plugin.js → executors/python/index.js} +6 -31
- package/plugins/{shell-executor-plugin.js → executors/shell/index.js} +2 -5
- package/plugins/install/README.md +9 -0
- package/plugins/{install-plugin.js → install/index.js} +3 -3
- package/plugins/{file-system-plugin.js → io/file-system/index.js} +34 -236
- package/plugins/{web-plugin.js → io/web/index.js} +11 -113
- package/plugins/memory/README.md +13 -0
- package/plugins/{memory-plugin.js → memory/index.js} +4 -18
- package/plugins/messaging/email/README.md +19 -0
- package/plugins/{email → messaging/email}/index.js +3 -3
- package/plugins/{feishu-plugin.js → messaging/feishu/index.js} +4 -4
- package/plugins/{qq-plugin.js → messaging/qq/index.js} +6 -17
- package/plugins/{telegram-plugin.js → messaging/telegram/index.js} +4 -4
- package/plugins/{weixin-plugin.js → messaging/weixin/index.js} +16 -16
- package/plugins/{plugin-manager-plugin.js → plugin-manager/index.js} +36 -180
- package/plugins/{tools-plugin.js → tools/index.js} +68 -116
- package/plugins/trading/README.md +15 -0
- package/plugins/{gate-trading.js → trading/index.js} +8 -8
- package/{examples → sandbox}/test-concurrent-chat.js +2 -2
- package/{examples → sandbox}/test-long-chat.js +2 -2
- package/{examples → sandbox}/test-session-chat.js +2 -2
- package/{examples → sandbox}/test-web-plugin.js +1 -1
- package/{examples → sandbox}/test-weixin-feishu.js +2 -2
- package/src/agent/base.js +56 -0
- package/src/{core/agent-chat.js → agent/chat.js} +11 -11
- package/src/{core/coordinator-manager.js → agent/coordinator.js} +3 -3
- package/src/agent/index.js +111 -0
- package/src/agent/main.js +337 -0
- package/src/agent/prompt.js +78 -0
- package/src/agent/sub.js +198 -0
- package/src/agent/worker.js +104 -0
- package/{cli/bin/foliko.js → src/cli/bin.js} +1 -1
- package/{cli/src → src/cli}/commands/chat.js +25 -21
- package/{cli/src → src/cli}/index.js +1 -0
- package/{cli/src → src/cli}/ui/chat-ui-old.js +40 -178
- package/{cli/src → src/cli}/ui/chat-ui.js +3 -3
- package/{cli/src → src/cli}/ui/components/footer-bar.js +1 -1
- package/src/common/errors.js +402 -0
- package/src/{utils → common}/logger.js +33 -0
- package/src/{utils/chat-queue.js → common/queue.js} +2 -2
- package/src/config/plugin-config.js +50 -0
- package/src/context/agent.js +32 -0
- package/src/context/compaction-prompts.js +170 -0
- package/src/context/compaction-utils.js +191 -0
- package/src/context/compressor.js +413 -0
- package/src/context/index.js +9 -0
- package/src/{core/context-manager.js → context/manager.js} +1 -1
- package/src/context/request.js +50 -0
- package/src/context/session.js +33 -0
- package/src/context/storage.js +30 -0
- package/src/executors/mcp-client.js +153 -0
- package/src/executors/mcp-desc.js +236 -0
- package/src/executors/mcp-executor.js +91 -956
- package/src/{core → framework}/command-registry.js +1 -1
- package/src/framework/framework.js +300 -0
- package/src/framework/index.js +18 -0
- package/src/framework/lifecycle.js +203 -0
- package/src/framework/loader.js +78 -0
- package/src/framework/registry.js +86 -0
- package/src/{core/ui-extension-context.js → framework/ui-extension.js} +1 -1
- package/src/index.js +130 -15
- package/src/llm/index.js +26 -0
- package/src/llm/provider.js +212 -0
- package/src/llm/registry.js +11 -0
- package/src/{core/token-counter.js → llm/tokens.js} +4 -37
- package/src/{core/plugin-base.js → plugin/base.js} +10 -136
- package/src/plugin/index.js +14 -0
- package/src/plugin/loader.js +101 -0
- package/src/plugin/manager.js +484 -0
- package/src/{core → session}/branch-summary-auto.js +2 -2
- package/src/{core/chat-session.js → session/chat.js} +2 -2
- package/src/session/index.js +7 -0
- package/src/{core/session-manager.js → session/session.js} +2 -2
- package/src/session/ttl.js +92 -0
- package/src/{core/jsonl-storage.js → storage/jsonl.js} +1 -1
- package/src/tool/executor.js +85 -0
- package/src/tool/index.js +15 -0
- package/src/tool/registry.js +143 -0
- package/src/{core/tool-router.js → tool/router.js} +17 -124
- package/src/tool/schema.js +108 -0
- package/src/utils/data-splitter.js +1 -1
- package/src/utils/download.js +1 -1
- package/src/utils/index.js +6 -6
- package/src/utils/message-validator.js +1 -1
- package/tests/core/context-storage.test.js +46 -0
- package/tests/core/llm.test.js +54 -0
- package/tests/core/plugin.test.js +42 -0
- package/tests/core/tool.test.js +60 -0
- package/tests/setup.js +10 -0
- package/tests/smoke.test.js +58 -0
- package/vitest.config.js +9 -0
- package/cli/src/daemon.js +0 -149
- package/docs/CONTEXT_DESIGN.md +0 -1596
- package/docs/ai-sdk-optimization.md +0 -655
- package/docs/features.md +0 -120
- package/docs/qq-bot.md +0 -976
- package/docs/quick-reference.md +0 -160
- package/docs/user-manual.md +0 -1391
- package/images/geometric_shapes.jpg +0 -0
- package/images/sunset_mountain_lake.jpg +0 -0
- package/skills/poster-guide/SKILL.md +0 -792
- package/src/capabilities/index.js +0 -11
- package/src/core/agent.js +0 -808
- package/src/core/context-compressor.js +0 -959
- package/src/core/enhanced-context-compressor.js +0 -210
- package/src/core/framework.js +0 -1422
- package/src/core/index.js +0 -30
- package/src/core/plugin-manager.js +0 -961
- package/src/core/provider-registry.js +0 -159
- package/src/core/provider.js +0 -156
- package/src/core/request-context.js +0 -98
- package/src/core/subagent.js +0 -442
- package/src/core/system-prompt-builder.js +0 -120
- package/src/core/tool-executor.js +0 -202
- package/src/core/tool-registry.js +0 -517
- package/src/core/worker-agent.js +0 -192
- package/src/executors/executor-base.js +0 -58
- package/src/utils/error-boundary.js +0 -363
- package/src/utils/error.js +0 -374
- package/system.md +0 -1645
- package/website_v2/README.md +0 -57
- package/website_v2/SPEC.md +0 -1
- package/website_v2/docs/api.html +0 -128
- package/website_v2/docs/configuration.html +0 -147
- package/website_v2/docs/plugin-development.html +0 -129
- package/website_v2/docs/project-structure.html +0 -89
- package/website_v2/docs/skill-development.html +0 -85
- package/website_v2/index.html +0 -489
- package/website_v2/scripts/main.js +0 -93
- package/website_v2/styles/animations.css +0 -8
- package/website_v2/styles/docs.css +0 -83
- package/website_v2/styles/main.css +0 -417
- package/xhs_auth.json +0 -268
- package//346/265/267/346/212/245/346/217/222/344/273/266.md +0 -621
- /package/plugins/{ambient-agent → ambient}/constants.js +0 -0
- /package/plugins/{email → messaging/email}/constants.js +0 -0
- /package/plugins/{email → messaging/email}/handlers.js +0 -0
- /package/plugins/{email → messaging/email}/monitor.js +0 -0
- /package/plugins/{email → messaging/email}/parser.js +0 -0
- /package/plugins/{email → messaging/email}/reply.js +0 -0
- /package/plugins/{email → messaging/email}/utils.js +0 -0
- /package/{examples → sandbox}/test-chat.js +0 -0
- /package/{examples → sandbox}/test-mcp.js +0 -0
- /package/{examples → sandbox}/test-reload.js +0 -0
- /package/{examples → sandbox}/test-telegram.js +0 -0
- /package/{examples → sandbox}/test-tg-bot.js +0 -0
- /package/{examples → sandbox}/test-tg-simple.js +0 -0
- /package/{examples → sandbox}/test-tg.js +0 -0
- /package/{examples → sandbox}/test-think.js +0 -0
- /package/src/{core/sub-agent-config.js → agent/sub-config.js} +0 -0
- /package/{cli/src → src/cli}/commands/daemon.js +0 -0
- /package/{cli/src → src/cli}/commands/list.js +0 -0
- /package/{cli/src → src/cli}/commands/plugin.js +0 -0
- /package/{cli/src → src/cli}/ui/components/agent-mention-provider.js +0 -0
- /package/{cli/src → src/cli}/ui/components/chained-autocomplete-provider.js +0 -0
- /package/{cli/src → src/cli}/ui/components/message-bubble.js +0 -0
- /package/{cli/src → src/cli}/ui/components/status-bar.js +0 -0
- /package/{cli/src → src/cli}/utils/ansi.js +0 -0
- /package/{cli/src → src/cli}/utils/config.js +0 -0
- /package/{cli/src → src/cli}/utils/markdown.js +0 -0
- /package/{cli/src → src/cli}/utils/plugin-config.js +0 -0
- /package/{cli/src → src/cli}/utils/render-diff.js +0 -0
- /package/src/{utils/circuit-breaker.js → common/circuit.js} +0 -0
- /package/src/{core → common}/constants.js +0 -0
- /package/src/{utils/edit-diff.js → common/diff.js} +0 -0
- /package/src/{utils/event-emitter.js → common/events.js} +0 -0
- /package/src/{utils → common}/id.js +0 -0
- /package/src/{utils → common}/retry.js +0 -0
- /package/src/{core/notification-manager.js → notification/manager.js} +0 -0
- /package/src/{core/session-entry.js → session/entry.js} +0 -0
- /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('
|
|
7
|
-
const { logger } = require('
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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('
|
|
6
|
-
const { Plugin } = require('
|
|
7
|
-
const { logger } = require('
|
|
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('
|
|
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
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
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
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
}
|
|
913
|
-
|
|
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
|
-
|
|
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
|
|
992
|
+
this._engine = new fresh.WorkflowEngine(framework);
|
|
966
993
|
// 注册内置步骤类型
|
|
967
|
-
this._engine.registerStepType(
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
);
|
|
971
|
-
this._engine.registerStepType(
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
);
|
|
975
|
-
this._engine.registerStepType(
|
|
976
|
-
|
|
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
|
*/
|