foliko 1.0.64 → 1.0.66
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 +145 -142
- package/cli/src/commands/chat.js +4 -1
- package/package.json +1 -1
- package/plugins/ai-plugin.js +2 -1
- package/plugins/ambient-agent-plugin.js +160 -48
- package/plugins/email.js +170 -18
- package/plugins/file-system-plugin.js +2 -2
- package/skills/ambient-agent/SKILL.md +234 -0
- package/skills/workflow-guide/SKILL.md +139 -73
- package/src/capabilities/workflow-engine.js +435 -127
- package/src/core/agent-chat.js +26 -4
- package/src/core/agent.js +1 -1
- package/src/core/framework.js +3 -3
|
@@ -20,75 +20,132 @@ const StepType = {
|
|
|
20
20
|
SEQUENTIAL: 'sequential',
|
|
21
21
|
LOOP: 'loop',
|
|
22
22
|
DELAY: 'delay',
|
|
23
|
+
TOOL: 'tool',
|
|
23
24
|
INPUT: 'input',
|
|
24
|
-
OUTPUT: 'output'
|
|
25
|
+
OUTPUT: 'output',
|
|
26
|
+
MESSAGE: 'message',
|
|
27
|
+
THINK: 'think'
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
|
-
*
|
|
31
|
+
* StepExecutor - 统一的步骤执行器
|
|
32
|
+
* 同时被 WorkflowEngine 和 ExplorerLoop 使用
|
|
29
33
|
*/
|
|
30
|
-
class
|
|
31
|
-
constructor(
|
|
32
|
-
this.
|
|
33
|
-
this.type = config.type
|
|
34
|
-
this.name = config.name || ''
|
|
35
|
-
this.description = config.description || ''
|
|
36
|
-
this.condition = config.condition || null
|
|
37
|
-
this.timeout = config.timeout || 30000
|
|
38
|
-
this.retry = config.retry || { enabled: false, maxAttempts: 3, delay: 1000 }
|
|
39
|
-
this.onSuccess = config.onSuccess || null
|
|
40
|
-
this.onFailure = config.onFailure || null
|
|
34
|
+
class StepExecutor {
|
|
35
|
+
constructor(framework) {
|
|
36
|
+
this.framework = framework
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
/**
|
|
40
|
+
* 执行单个步骤
|
|
41
|
+
*/
|
|
42
|
+
async executeStep(step, context) {
|
|
43
|
+
const handler = this._getStepHandler(step.type)
|
|
44
|
+
if (!handler) {
|
|
45
|
+
throw new Error(`Unknown step type: ${step.type}`)
|
|
46
|
+
}
|
|
47
|
+
return await handler.call(this, step, context)
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
/**
|
|
51
|
+
* 执行多个步骤(顺序)
|
|
52
|
+
*/
|
|
53
|
+
async executeSteps(steps, context) {
|
|
54
|
+
const results = []
|
|
55
|
+
for (const step of steps) {
|
|
56
|
+
const result = await this.executeStep(step, context)
|
|
57
|
+
results.push(result)
|
|
50
58
|
}
|
|
51
|
-
return
|
|
59
|
+
return results
|
|
52
60
|
}
|
|
53
|
-
}
|
|
54
61
|
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
/**
|
|
63
|
+
* 获取步骤类型处理器
|
|
64
|
+
*/
|
|
65
|
+
_getStepHandler(type) {
|
|
66
|
+
const handlers = {
|
|
67
|
+
[StepType.TOOL]: this.executeTool,
|
|
68
|
+
[StepType.SCRIPT]: this.executeScript,
|
|
69
|
+
[StepType.CONDITION]: this.executeCondition,
|
|
70
|
+
[StepType.LOOP]: this.executeLoop,
|
|
71
|
+
[StepType.DELAY]: this.executeDelay,
|
|
72
|
+
[StepType.SEQUENTIAL]: this.executeSequential,
|
|
73
|
+
[StepType.MESSAGE]: this.executeMessage,
|
|
74
|
+
[StepType.THINK]: this.executeThink
|
|
75
|
+
}
|
|
76
|
+
return handlers[type]
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
/**
|
|
80
|
+
* 执行工具步骤
|
|
81
|
+
*/
|
|
82
|
+
async executeTool(step, context) {
|
|
83
|
+
if (!step.tool) {
|
|
84
|
+
throw new Error('Tool step requires a tool name')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(`[StepExecutor] Executing tool: ${step.tool}`)
|
|
88
|
+
|
|
89
|
+
// 解析工具参数,支持变量引用
|
|
90
|
+
const resolvedArgs = this._resolveArgs(step.args || {}, context)
|
|
91
|
+
|
|
92
|
+
// 获取当前 sessionId
|
|
93
|
+
let sessionId = context.variables?._sessionId
|
|
94
|
+
if (!sessionId && this.framework.getExecutionContext) {
|
|
95
|
+
const ctx = this.framework.getExecutionContext()
|
|
96
|
+
sessionId = ctx?.sessionId
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 执行工具
|
|
100
|
+
let result
|
|
101
|
+
if (sessionId && this.framework.runWithContext) {
|
|
102
|
+
result = await this.framework.runWithContext(
|
|
103
|
+
{ sessionId },
|
|
104
|
+
async () => await this.framework.executeTool(step.tool, resolvedArgs)
|
|
105
|
+
)
|
|
106
|
+
} else {
|
|
107
|
+
result = await this.framework.executeTool(step.tool, resolvedArgs)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 保存结果到变量
|
|
111
|
+
if (step.outputVariable) {
|
|
112
|
+
context.variables[step.outputVariable] = result
|
|
113
|
+
}
|
|
114
|
+
context.lastResult = result
|
|
115
|
+
|
|
116
|
+
if (result && result.error) {
|
|
117
|
+
console.warn(`[StepExecutor] Tool ${step.tool} returned error: ${result.error}`)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return result
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 执行脚本步骤
|
|
125
|
+
*/
|
|
126
|
+
async executeScript(step, context) {
|
|
127
|
+
console.log(`[StepExecutor] Executing script step: ${step.name || step.id}`)
|
|
67
128
|
|
|
68
129
|
try {
|
|
69
|
-
// 创建安全的脚本执行环境
|
|
70
130
|
const scriptContext = {
|
|
71
131
|
input: context.input,
|
|
72
132
|
variables: context.variables,
|
|
73
133
|
previousResult: context.lastResult,
|
|
74
134
|
console: {
|
|
75
|
-
log: (...args) => console.log(`[Script:${
|
|
135
|
+
log: (...args) => console.log(`[Script:${step.id}]`, ...args)
|
|
76
136
|
}
|
|
77
137
|
}
|
|
78
138
|
|
|
79
|
-
// 执行脚本
|
|
80
139
|
let result
|
|
81
|
-
if (typeof
|
|
82
|
-
result = await
|
|
83
|
-
} else if (typeof
|
|
84
|
-
|
|
85
|
-
const fn = new Function('context', `return (async () => { ${this.script} })()`)
|
|
140
|
+
if (typeof step.script === 'function') {
|
|
141
|
+
result = await step.script(scriptContext)
|
|
142
|
+
} else if (typeof step.script === 'string') {
|
|
143
|
+
const fn = new Function('context', `return (async () => { ${step.script} })()`)
|
|
86
144
|
result = await fn(scriptContext)
|
|
87
145
|
}
|
|
88
146
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
context.variables[this.outputVariable] = result
|
|
147
|
+
if (step.outputVariable) {
|
|
148
|
+
context.variables[step.outputVariable] = result
|
|
92
149
|
}
|
|
93
150
|
context.lastResult = result
|
|
94
151
|
|
|
@@ -97,61 +154,288 @@ class ScriptStep extends WorkflowStep {
|
|
|
97
154
|
throw new Error(`Script execution failed: ${err.message}`)
|
|
98
155
|
}
|
|
99
156
|
}
|
|
100
|
-
}
|
|
101
157
|
|
|
102
|
-
/**
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
super({ ...config, type: StepType.CONDITION })
|
|
108
|
-
this.branches = config.branches || []
|
|
109
|
-
this.defaultBranch = config.defaultBranch || null
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async execute(context, engine) {
|
|
113
|
-
console.log(`[Workflow] Evaluating condition: ${this.name || this.id}`)
|
|
158
|
+
/**
|
|
159
|
+
* 执行条件步骤
|
|
160
|
+
*/
|
|
161
|
+
async executeCondition(step, context) {
|
|
162
|
+
console.log(`[StepExecutor] Evaluating condition: ${step.name || step.id}`)
|
|
114
163
|
|
|
115
|
-
for (const branch of
|
|
164
|
+
for (const branch of (step.branches || [])) {
|
|
116
165
|
try {
|
|
117
166
|
let conditionValue
|
|
118
167
|
if (typeof branch.condition === 'function') {
|
|
119
168
|
conditionValue = branch.condition(context)
|
|
120
169
|
} else if (typeof branch.condition === 'string') {
|
|
121
|
-
// eslint-disable-next-line no-new-func
|
|
122
170
|
const fn = new Function('context', `with(context.variables) { return (${branch.condition}) }`)
|
|
123
171
|
conditionValue = fn(context)
|
|
124
172
|
}
|
|
125
173
|
|
|
126
174
|
if (conditionValue) {
|
|
127
|
-
console.log(`[
|
|
175
|
+
console.log(`[StepExecutor] Condition matched: ${branch.name || branch.stepId}`)
|
|
128
176
|
|
|
129
177
|
if (branch.steps && branch.steps.length > 0) {
|
|
130
|
-
|
|
131
|
-
for (const stepConfig of branch.steps) {
|
|
132
|
-
const step = engine.createStep(stepConfig)
|
|
133
|
-
await step.execute(context, engine)
|
|
134
|
-
}
|
|
178
|
+
await this.executeSteps(branch.steps, context)
|
|
135
179
|
}
|
|
136
180
|
|
|
137
|
-
return branch.stepId
|
|
181
|
+
return branch.stepId || branch.name
|
|
138
182
|
}
|
|
139
183
|
} catch (err) {
|
|
140
|
-
console.warn(`[
|
|
184
|
+
console.warn(`[StepExecutor] Branch condition error:`, err.message)
|
|
141
185
|
}
|
|
142
186
|
}
|
|
143
187
|
|
|
144
188
|
// 执行默认分支
|
|
145
|
-
if (
|
|
146
|
-
console.log(`[
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
189
|
+
if (step.defaultBranch && step.defaultBranch.steps) {
|
|
190
|
+
console.log(`[StepExecutor] Executing default branch`)
|
|
191
|
+
await this.executeSteps(step.defaultBranch.steps, context)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 执行循环步骤
|
|
199
|
+
*/
|
|
200
|
+
async executeLoop(step, context) {
|
|
201
|
+
console.log(`[StepExecutor] Executing loop: ${step.name || step.id}`)
|
|
202
|
+
|
|
203
|
+
const results = []
|
|
204
|
+
const maxIterations = step.maxIterations || 10
|
|
205
|
+
const loopVariable = step.loopVariable || 'loopIndex'
|
|
206
|
+
|
|
207
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
208
|
+
context.variables[loopVariable] = i
|
|
209
|
+
console.log(`[StepExecutor] Loop iteration ${i}`)
|
|
210
|
+
|
|
211
|
+
const iterationResults = []
|
|
212
|
+
for (const stepConfig of (step.steps || [])) {
|
|
213
|
+
const result = await this.executeStep(stepConfig, context)
|
|
214
|
+
iterationResults.push(result)
|
|
215
|
+
}
|
|
216
|
+
results.push(iterationResults)
|
|
217
|
+
|
|
218
|
+
// 检查终止条件
|
|
219
|
+
if (step.until) {
|
|
220
|
+
let shouldStop = false
|
|
221
|
+
if (typeof step.until === 'function') {
|
|
222
|
+
shouldStop = step.until(context)
|
|
223
|
+
} else if (typeof step.until === 'string') {
|
|
224
|
+
const fn = new Function('context', `with(context.variables) { return (${step.until}) }`)
|
|
225
|
+
shouldStop = fn(context)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (shouldStop) {
|
|
229
|
+
console.log(`[StepExecutor] Loop terminated at iteration ${i}`)
|
|
230
|
+
break
|
|
231
|
+
}
|
|
150
232
|
}
|
|
151
233
|
}
|
|
152
234
|
|
|
235
|
+
return results
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 执行延迟步骤
|
|
240
|
+
*/
|
|
241
|
+
async executeDelay(step, context) {
|
|
242
|
+
const delayMs = step.delayMs || 1000
|
|
243
|
+
console.log(`[StepExecutor] Delaying ${delayMs}ms`)
|
|
244
|
+
await new Promise(resolve => setTimeout(resolve, delayMs))
|
|
153
245
|
return null
|
|
154
246
|
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 执行顺序步骤
|
|
250
|
+
*/
|
|
251
|
+
async executeSequential(step, context) {
|
|
252
|
+
console.log(`[StepExecutor] Executing sequential: ${step.name || step.id}`)
|
|
253
|
+
return await this.executeSteps(step.steps || [], context)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* 执行消息步骤(ExplorerLoop 专用)
|
|
258
|
+
*/
|
|
259
|
+
async executeMessage(step, context) {
|
|
260
|
+
console.log(`[StepExecutor] Executing message step`)
|
|
261
|
+
|
|
262
|
+
const agent = this._getActiveAgent()
|
|
263
|
+
if (!agent) {
|
|
264
|
+
return { success: false, error: '没有可用的代理' }
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
let content = step.content || ''
|
|
268
|
+
// 支持变量引用
|
|
269
|
+
content = this._resolveValue(content, context)
|
|
270
|
+
|
|
271
|
+
// 如果有事件上下文,附加到消息
|
|
272
|
+
if (context.variables?._event) {
|
|
273
|
+
content = `${content}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const result = await agent.pushMessage(content)
|
|
277
|
+
return { success: true, result }
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* 执行思考步骤(ExplorerLoop 专用)
|
|
282
|
+
*/
|
|
283
|
+
async executeThink(step, context) {
|
|
284
|
+
console.log(`[StepExecutor] Executing think step`)
|
|
285
|
+
|
|
286
|
+
const thinkPlugin = this.framework.pluginManager?.get('think')
|
|
287
|
+
if (!thinkPlugin) {
|
|
288
|
+
return { success: false, error: '思考插件不可用' }
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
let topic = step.topic || 'Ambient代理反思'
|
|
292
|
+
topic = this._resolveValue(topic, context)
|
|
293
|
+
|
|
294
|
+
if (context.variables?._event) {
|
|
295
|
+
topic = `${topic}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const result = await thinkPlugin._triggerThinking({
|
|
299
|
+
topic,
|
|
300
|
+
mode: step.mode || 'reflect',
|
|
301
|
+
depth: step.depth || 2
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
return result
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* 获取活跃代理
|
|
309
|
+
*/
|
|
310
|
+
_getActiveAgent() {
|
|
311
|
+
if (this.framework._mainAgent) {
|
|
312
|
+
return this.framework._mainAgent
|
|
313
|
+
}
|
|
314
|
+
const agents = this.framework._agents || []
|
|
315
|
+
return agents.length > 0 ? agents[agents.length - 1] : null
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* 解析参数中的变量引用
|
|
320
|
+
*/
|
|
321
|
+
_resolveArgs(args, context) {
|
|
322
|
+
const resolved = {}
|
|
323
|
+
for (const [key, value] of Object.entries(args)) {
|
|
324
|
+
resolved[key] = this._resolveValue(value, context)
|
|
325
|
+
}
|
|
326
|
+
return resolved
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
_resolveValue(value, context) {
|
|
330
|
+
if (typeof value === 'string') {
|
|
331
|
+
return value.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
|
|
332
|
+
if (path.startsWith('variables.')) {
|
|
333
|
+
return this._getNestedValue(context, path) ?? match
|
|
334
|
+
} else if (path.startsWith('context.')) {
|
|
335
|
+
return this._getNestedValue(context, path) ?? match
|
|
336
|
+
} else {
|
|
337
|
+
const val = this._getNestedValue(context.variables, path)
|
|
338
|
+
if (val !== undefined) return val
|
|
339
|
+
return this._getNestedValue(context, path) ?? match
|
|
340
|
+
}
|
|
341
|
+
})
|
|
342
|
+
} else if (Array.isArray(value)) {
|
|
343
|
+
return value.map(v => this._resolveValue(v, context))
|
|
344
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
345
|
+
const resolved = {}
|
|
346
|
+
for (const [k, v] of Object.entries(value)) {
|
|
347
|
+
resolved[k] = this._resolveValue(v, context)
|
|
348
|
+
}
|
|
349
|
+
return resolved
|
|
350
|
+
}
|
|
351
|
+
return value
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
_getNestedValue(obj, path) {
|
|
355
|
+
if (!obj) return undefined
|
|
356
|
+
const parts = path.split('.')
|
|
357
|
+
let current = obj
|
|
358
|
+
for (const part of parts) {
|
|
359
|
+
if (current === null || current === undefined) return undefined
|
|
360
|
+
current = current[part]
|
|
361
|
+
}
|
|
362
|
+
return current
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 工作流步骤基类
|
|
368
|
+
*/
|
|
369
|
+
class WorkflowStep {
|
|
370
|
+
constructor(config) {
|
|
371
|
+
this.id = config.id || `step_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
372
|
+
this.type = config.type
|
|
373
|
+
this.name = config.name || ''
|
|
374
|
+
this.description = config.description || ''
|
|
375
|
+
this.condition = config.condition || null
|
|
376
|
+
this.timeout = config.timeout || 30000
|
|
377
|
+
this.retry = config.retry || { enabled: false, maxAttempts: 3, delay: 1000 }
|
|
378
|
+
this.onSuccess = config.onSuccess || null
|
|
379
|
+
this.onFailure = config.onFailure || null
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async execute(context, engine) {
|
|
383
|
+
throw new Error('execute() must be implemented by subclass')
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
validate() {
|
|
387
|
+
if (!this.type) {
|
|
388
|
+
throw new Error('Step must have a type')
|
|
389
|
+
}
|
|
390
|
+
return true
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 脚本步骤
|
|
396
|
+
*/
|
|
397
|
+
class ScriptStep extends WorkflowStep {
|
|
398
|
+
constructor(config) {
|
|
399
|
+
super({ ...config, type: StepType.SCRIPT })
|
|
400
|
+
this.script = config.script
|
|
401
|
+
this.outputVariable = config.outputVariable || null
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
async execute(context, engine) {
|
|
405
|
+
// 使用 StepExecutor 执行脚本逻辑
|
|
406
|
+
const executor = new StepExecutor(engine.framework)
|
|
407
|
+
const stepConfig = {
|
|
408
|
+
id: this.id,
|
|
409
|
+
name: this.name,
|
|
410
|
+
type: StepType.SCRIPT,
|
|
411
|
+
script: this.script,
|
|
412
|
+
outputVariable: this.outputVariable
|
|
413
|
+
}
|
|
414
|
+
return await executor.executeScript(stepConfig, context)
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* 条件步骤
|
|
420
|
+
*/
|
|
421
|
+
class ConditionStep extends WorkflowStep {
|
|
422
|
+
constructor(config) {
|
|
423
|
+
super({ ...config, type: StepType.CONDITION })
|
|
424
|
+
this.branches = config.branches || []
|
|
425
|
+
this.defaultBranch = config.defaultBranch || null
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async execute(context, engine) {
|
|
429
|
+
const executor = new StepExecutor(engine.framework)
|
|
430
|
+
const stepConfig = {
|
|
431
|
+
id: this.id,
|
|
432
|
+
name: this.name,
|
|
433
|
+
type: StepType.CONDITION,
|
|
434
|
+
branches: this.branches,
|
|
435
|
+
defaultBranch: this.defaultBranch
|
|
436
|
+
}
|
|
437
|
+
return await executor.executeCondition(stepConfig, context)
|
|
438
|
+
}
|
|
155
439
|
}
|
|
156
440
|
|
|
157
441
|
/**
|
|
@@ -164,17 +448,14 @@ class SequentialStep extends WorkflowStep {
|
|
|
164
448
|
}
|
|
165
449
|
|
|
166
450
|
async execute(context, engine) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const result = await step.execute(context, engine)
|
|
174
|
-
results.push(result)
|
|
451
|
+
const executor = new StepExecutor(engine.framework)
|
|
452
|
+
const stepConfig = {
|
|
453
|
+
id: this.id,
|
|
454
|
+
name: this.name,
|
|
455
|
+
type: StepType.SEQUENTIAL,
|
|
456
|
+
steps: this.steps
|
|
175
457
|
}
|
|
176
|
-
|
|
177
|
-
return results
|
|
458
|
+
return await executor.executeSequential(stepConfig, context)
|
|
178
459
|
}
|
|
179
460
|
}
|
|
180
461
|
|
|
@@ -187,44 +468,21 @@ class LoopStep extends WorkflowStep {
|
|
|
187
468
|
this.maxIterations = config.maxIterations || 10
|
|
188
469
|
this.loopVariable = config.loopVariable || 'loopIndex'
|
|
189
470
|
this.steps = config.steps || []
|
|
190
|
-
this.until = config.until || null
|
|
471
|
+
this.until = config.until || null
|
|
191
472
|
}
|
|
192
473
|
|
|
193
474
|
async execute(context, engine) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
for (const stepConfig of this.steps) {
|
|
204
|
-
const step = engine.createStep(stepConfig)
|
|
205
|
-
const result = await step.execute(context, engine)
|
|
206
|
-
results.push(result)
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// 检查终止条件
|
|
210
|
-
if (this.until) {
|
|
211
|
-
let shouldStop = false
|
|
212
|
-
if (typeof this.until === 'function') {
|
|
213
|
-
shouldStop = this.until(context)
|
|
214
|
-
} else if (typeof this.until === 'string') {
|
|
215
|
-
// eslint-disable-next-line no-new-func
|
|
216
|
-
const fn = new Function('context', `with(context.variables) { return (${this.until}) }`)
|
|
217
|
-
shouldStop = fn(context)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (shouldStop) {
|
|
221
|
-
console.log(`[Workflow] Loop terminated at iteration ${i}`)
|
|
222
|
-
break
|
|
223
|
-
}
|
|
224
|
-
}
|
|
475
|
+
const executor = new StepExecutor(engine.framework)
|
|
476
|
+
const stepConfig = {
|
|
477
|
+
id: this.id,
|
|
478
|
+
name: this.name,
|
|
479
|
+
type: StepType.LOOP,
|
|
480
|
+
maxIterations: this.maxIterations,
|
|
481
|
+
loopVariable: this.loopVariable,
|
|
482
|
+
steps: this.steps,
|
|
483
|
+
until: this.until
|
|
225
484
|
}
|
|
226
|
-
|
|
227
|
-
return results
|
|
485
|
+
return await executor.executeLoop(stepConfig, context)
|
|
228
486
|
}
|
|
229
487
|
}
|
|
230
488
|
|
|
@@ -238,9 +496,39 @@ class DelayStep extends WorkflowStep {
|
|
|
238
496
|
}
|
|
239
497
|
|
|
240
498
|
async execute(context, engine) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
499
|
+
const executor = new StepExecutor(engine.framework)
|
|
500
|
+
const stepConfig = {
|
|
501
|
+
id: this.id,
|
|
502
|
+
name: this.name,
|
|
503
|
+
type: StepType.DELAY,
|
|
504
|
+
delayMs: this.delayMs
|
|
505
|
+
}
|
|
506
|
+
return await executor.executeDelay(stepConfig, context)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* 工具步骤
|
|
512
|
+
*/
|
|
513
|
+
class ToolStep extends WorkflowStep {
|
|
514
|
+
constructor(config) {
|
|
515
|
+
super({ ...config, type: StepType.TOOL })
|
|
516
|
+
this.tool = config.tool
|
|
517
|
+
this.args = config.args || {}
|
|
518
|
+
this.outputVariable = config.outputVariable || null
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
async execute(context, engine) {
|
|
522
|
+
const executor = new StepExecutor(engine.framework)
|
|
523
|
+
const stepConfig = {
|
|
524
|
+
id: this.id,
|
|
525
|
+
name: this.name,
|
|
526
|
+
type: StepType.TOOL,
|
|
527
|
+
tool: this.tool,
|
|
528
|
+
args: this.args,
|
|
529
|
+
outputVariable: this.outputVariable
|
|
530
|
+
}
|
|
531
|
+
return await executor.executeTool(stepConfig, context)
|
|
244
532
|
}
|
|
245
533
|
}
|
|
246
534
|
|
|
@@ -316,6 +604,7 @@ class WorkflowPlugin extends Plugin {
|
|
|
316
604
|
this._engine.registerStepType(StepType.SEQUENTIAL, SequentialStep)
|
|
317
605
|
this._engine.registerStepType(StepType.LOOP, LoopStep)
|
|
318
606
|
this._engine.registerStepType(StepType.DELAY, DelayStep)
|
|
607
|
+
this._engine.registerStepType(StepType.TOOL, ToolStep)
|
|
319
608
|
|
|
320
609
|
// 注册工作流执行工具
|
|
321
610
|
framework.registerTool({
|
|
@@ -325,8 +614,14 @@ class WorkflowPlugin extends Plugin {
|
|
|
325
614
|
workflow: z.string().describe('工作流定义(JSON 或 JavaScript 代码)'),
|
|
326
615
|
input: z.object({}).optional().describe('工作流输入参数')
|
|
327
616
|
}),
|
|
328
|
-
execute: async (args) => {
|
|
329
|
-
|
|
617
|
+
execute: async (args, framework) => {
|
|
618
|
+
// 获取当前 sessionId
|
|
619
|
+
let sessionId = null
|
|
620
|
+
const ctx = framework.getExecutionContext()
|
|
621
|
+
if (ctx?.sessionId) {
|
|
622
|
+
sessionId = ctx.sessionId
|
|
623
|
+
}
|
|
624
|
+
return await this.executeWorkflow(args.workflow, args.input || {}, sessionId)
|
|
330
625
|
}
|
|
331
626
|
})
|
|
332
627
|
|
|
@@ -455,18 +750,24 @@ class WorkflowPlugin extends Plugin {
|
|
|
455
750
|
/**
|
|
456
751
|
* 执行工作流
|
|
457
752
|
*/
|
|
458
|
-
async executeWorkflow(workflowDef, input = {}) {
|
|
753
|
+
async executeWorkflow(workflowDef, input = {}, sessionId = null) {
|
|
459
754
|
try {
|
|
460
755
|
let workflow
|
|
461
756
|
|
|
462
757
|
if (typeof workflowDef === 'string') {
|
|
463
|
-
//
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
758
|
+
// 尝试作为工作流名称加载(先检查是否已加载的工作流)
|
|
759
|
+
const workflowName = workflowDef.trim()
|
|
760
|
+
if (this._workflows.has(workflowName)) {
|
|
761
|
+
workflow = this._workflows.get(workflowName)
|
|
762
|
+
} else {
|
|
763
|
+
// 尝试解析 JSON 或执行代码
|
|
764
|
+
try {
|
|
765
|
+
workflow = JSON.parse(workflowDef)
|
|
766
|
+
} catch {
|
|
767
|
+
// eslint-disable-next-line no-new-func
|
|
768
|
+
const fn = new Function('engine', 'return (' + workflowDef + ')')
|
|
769
|
+
workflow = fn(this._engine)
|
|
770
|
+
}
|
|
470
771
|
}
|
|
471
772
|
} else {
|
|
472
773
|
workflow = workflowDef
|
|
@@ -474,6 +775,11 @@ class WorkflowPlugin extends Plugin {
|
|
|
474
775
|
|
|
475
776
|
const context = this._engine.createContext(input, {})
|
|
476
777
|
|
|
778
|
+
// 将 sessionId 存储到上下文变量,供工具步骤使用
|
|
779
|
+
if (sessionId) {
|
|
780
|
+
context.variables._sessionId = sessionId
|
|
781
|
+
}
|
|
782
|
+
|
|
477
783
|
// 执行工作流步骤
|
|
478
784
|
if (workflow.steps && Array.isArray(workflow.steps)) {
|
|
479
785
|
const results = []
|
|
@@ -509,9 +815,11 @@ module.exports = {
|
|
|
509
815
|
WorkflowEngine,
|
|
510
816
|
WorkflowStep,
|
|
511
817
|
StepType,
|
|
818
|
+
StepExecutor,
|
|
512
819
|
ScriptStep,
|
|
513
820
|
ConditionStep,
|
|
514
821
|
SequentialStep,
|
|
515
822
|
LoopStep,
|
|
516
|
-
DelayStep
|
|
823
|
+
DelayStep,
|
|
824
|
+
ToolStep
|
|
517
825
|
}
|