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.
@@ -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 WorkflowStep {
31
- constructor(config) {
32
- this.id = config.id || `step_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
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
- async execute(context, engine) {
44
- throw new Error('execute() must be implemented by subclass')
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
- validate() {
48
- if (!this.type) {
49
- throw new Error('Step must have a type')
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 true
59
+ return results
52
60
  }
53
- }
54
61
 
55
- /**
56
- * 脚本步骤
57
- */
58
- class ScriptStep extends WorkflowStep {
59
- constructor(config) {
60
- super({ ...config, type: StepType.SCRIPT })
61
- this.script = config.script
62
- this.outputVariable = config.outputVariable || null
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
- async execute(context, engine) {
66
- console.log(`[Workflow] Executing script step: ${this.name || this.id}`)
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:${this.id}]`, ...args)
135
+ log: (...args) => console.log(`[Script:${step.id}]`, ...args)
76
136
  }
77
137
  }
78
138
 
79
- // 执行脚本
80
139
  let result
81
- if (typeof this.script === 'function') {
82
- result = await this.script(scriptContext)
83
- } else if (typeof this.script === 'string') {
84
- // eslint-disable-next-line no-new-func
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
- if (this.outputVariable) {
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
- class ConditionStep extends WorkflowStep {
106
- constructor(config) {
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 this.branches) {
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(`[Workflow] Condition matched: ${branch.name || branch.stepId}`)
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(`[Workflow] Branch condition error:`, err.message)
184
+ console.warn(`[StepExecutor] Branch condition error:`, err.message)
141
185
  }
142
186
  }
143
187
 
144
188
  // 执行默认分支
145
- if (this.defaultBranch && this.defaultBranch.steps) {
146
- console.log(`[Workflow] Executing default branch`)
147
- for (const stepConfig of this.defaultBranch.steps) {
148
- const step = engine.createStep(stepConfig)
149
- await step.execute(context, engine)
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
- console.log(`[Workflow] Executing sequential: ${this.name || this.id}`)
168
-
169
- const results = []
170
-
171
- for (const stepConfig of this.steps) {
172
- const step = engine.createStep(stepConfig)
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
- console.log(`[Workflow] Executing loop: ${this.name || this.id}`)
195
-
196
- const results = []
197
-
198
- for (let i = 0; i < this.maxIterations; i++) {
199
- context.variables[this.loopVariable] = i
200
-
201
- console.log(`[Workflow] Loop iteration ${i}`)
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
- console.log(`[Workflow] Delaying ${this.delayMs}ms`)
242
- await new Promise(resolve => setTimeout(resolve, this.delayMs))
243
- return null
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
- return await this.executeWorkflow(args.workflow, args.input || {})
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
- // 尝试解析 JSON 或执行代码
464
- try {
465
- workflow = JSON.parse(workflowDef)
466
- } catch {
467
- // eslint-disable-next-line no-new-func
468
- const fn = new Function('engine', 'return (' + workflowDef + ')')
469
- workflow = fn(this._engine)
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
  }