foliko 1.0.65 → 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.
@@ -22,74 +22,130 @@ const StepType = {
22
22
  DELAY: 'delay',
23
23
  TOOL: 'tool',
24
24
  INPUT: 'input',
25
- OUTPUT: 'output'
25
+ OUTPUT: 'output',
26
+ MESSAGE: 'message',
27
+ THINK: 'think'
26
28
  }
27
29
 
28
30
  /**
29
- * 工作流步骤基类
31
+ * StepExecutor - 统一的步骤执行器
32
+ * 同时被 WorkflowEngine 和 ExplorerLoop 使用
30
33
  */
31
- class WorkflowStep {
32
- constructor(config) {
33
- this.id = config.id || `step_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
34
- this.type = config.type
35
- this.name = config.name || ''
36
- this.description = config.description || ''
37
- this.condition = config.condition || null
38
- this.timeout = config.timeout || 30000
39
- this.retry = config.retry || { enabled: false, maxAttempts: 3, delay: 1000 }
40
- this.onSuccess = config.onSuccess || null
41
- this.onFailure = config.onFailure || null
34
+ class StepExecutor {
35
+ constructor(framework) {
36
+ this.framework = framework
42
37
  }
43
38
 
44
- async execute(context, engine) {
45
- 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)
46
48
  }
47
49
 
48
- validate() {
49
- if (!this.type) {
50
- 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)
51
58
  }
52
- return true
59
+ return results
53
60
  }
54
- }
55
61
 
56
- /**
57
- * 脚本步骤
58
- */
59
- class ScriptStep extends WorkflowStep {
60
- constructor(config) {
61
- super({ ...config, type: StepType.SCRIPT })
62
- this.script = config.script
63
- 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]
64
77
  }
65
78
 
66
- async execute(context, engine) {
67
- 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}`)
68
128
 
69
129
  try {
70
- // 创建安全的脚本执行环境
71
130
  const scriptContext = {
72
131
  input: context.input,
73
132
  variables: context.variables,
74
133
  previousResult: context.lastResult,
75
134
  console: {
76
- log: (...args) => console.log(`[Script:${this.id}]`, ...args)
135
+ log: (...args) => console.log(`[Script:${step.id}]`, ...args)
77
136
  }
78
137
  }
79
138
 
80
- // 执行脚本
81
139
  let result
82
- if (typeof this.script === 'function') {
83
- result = await this.script(scriptContext)
84
- } else if (typeof this.script === 'string') {
85
- // eslint-disable-next-line no-new-func
86
- 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} })()`)
87
144
  result = await fn(scriptContext)
88
145
  }
89
146
 
90
- // 保存结果到变量
91
- if (this.outputVariable) {
92
- context.variables[this.outputVariable] = result
147
+ if (step.outputVariable) {
148
+ context.variables[step.outputVariable] = result
93
149
  }
94
150
  context.lastResult = result
95
151
 
@@ -98,128 +154,79 @@ class ScriptStep extends WorkflowStep {
98
154
  throw new Error(`Script execution failed: ${err.message}`)
99
155
  }
100
156
  }
101
- }
102
-
103
- /**
104
- * 条件步骤
105
- */
106
- class ConditionStep extends WorkflowStep {
107
- constructor(config) {
108
- super({ ...config, type: StepType.CONDITION })
109
- this.branches = config.branches || []
110
- this.defaultBranch = config.defaultBranch || null
111
- }
112
157
 
113
- async execute(context, engine) {
114
- 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}`)
115
163
 
116
- for (const branch of this.branches) {
164
+ for (const branch of (step.branches || [])) {
117
165
  try {
118
166
  let conditionValue
119
167
  if (typeof branch.condition === 'function') {
120
168
  conditionValue = branch.condition(context)
121
169
  } else if (typeof branch.condition === 'string') {
122
- // eslint-disable-next-line no-new-func
123
170
  const fn = new Function('context', `with(context.variables) { return (${branch.condition}) }`)
124
171
  conditionValue = fn(context)
125
172
  }
126
173
 
127
174
  if (conditionValue) {
128
- console.log(`[Workflow] Condition matched: ${branch.name || branch.stepId}`)
175
+ console.log(`[StepExecutor] Condition matched: ${branch.name || branch.stepId}`)
129
176
 
130
177
  if (branch.steps && branch.steps.length > 0) {
131
- // 执行分支步骤
132
- for (const stepConfig of branch.steps) {
133
- const step = engine.createStep(stepConfig)
134
- await step.execute(context, engine)
135
- }
178
+ await this.executeSteps(branch.steps, context)
136
179
  }
137
180
 
138
- return branch.stepId
181
+ return branch.stepId || branch.name
139
182
  }
140
183
  } catch (err) {
141
- console.warn(`[Workflow] Branch condition error:`, err.message)
184
+ console.warn(`[StepExecutor] Branch condition error:`, err.message)
142
185
  }
143
186
  }
144
187
 
145
188
  // 执行默认分支
146
- if (this.defaultBranch && this.defaultBranch.steps) {
147
- console.log(`[Workflow] Executing default branch`)
148
- for (const stepConfig of this.defaultBranch.steps) {
149
- const step = engine.createStep(stepConfig)
150
- await step.execute(context, engine)
151
- }
189
+ if (step.defaultBranch && step.defaultBranch.steps) {
190
+ console.log(`[StepExecutor] Executing default branch`)
191
+ await this.executeSteps(step.defaultBranch.steps, context)
152
192
  }
153
193
 
154
194
  return null
155
195
  }
156
- }
157
196
 
158
- /**
159
- * 顺序步骤
160
- */
161
- class SequentialStep extends WorkflowStep {
162
- constructor(config) {
163
- super({ ...config, type: StepType.SEQUENTIAL })
164
- this.steps = config.steps || []
165
- }
166
-
167
- async execute(context, engine) {
168
- console.log(`[Workflow] Executing sequential: ${this.name || this.id}`)
169
-
170
- const results = []
171
-
172
- for (const stepConfig of this.steps) {
173
- const step = engine.createStep(stepConfig)
174
- const result = await step.execute(context, engine)
175
- results.push(result)
176
- }
177
-
178
- return results
179
- }
180
- }
181
-
182
- /**
183
- * 循环步骤
184
- */
185
- class LoopStep extends WorkflowStep {
186
- constructor(config) {
187
- super({ ...config, type: StepType.LOOP })
188
- this.maxIterations = config.maxIterations || 10
189
- this.loopVariable = config.loopVariable || 'loopIndex'
190
- this.steps = config.steps || []
191
- this.until = config.until || null // 终止条件
192
- }
193
-
194
- async execute(context, engine) {
195
- console.log(`[Workflow] Executing loop: ${this.name || this.id}`)
197
+ /**
198
+ * 执行循环步骤
199
+ */
200
+ async executeLoop(step, context) {
201
+ console.log(`[StepExecutor] Executing loop: ${step.name || step.id}`)
196
202
 
197
203
  const results = []
204
+ const maxIterations = step.maxIterations || 10
205
+ const loopVariable = step.loopVariable || 'loopIndex'
198
206
 
199
- for (let i = 0; i < this.maxIterations; i++) {
200
- context.variables[this.loopVariable] = i
201
-
202
- console.log(`[Workflow] Loop iteration ${i}`)
207
+ for (let i = 0; i < maxIterations; i++) {
208
+ context.variables[loopVariable] = i
209
+ console.log(`[StepExecutor] Loop iteration ${i}`)
203
210
 
204
- for (const stepConfig of this.steps) {
205
- const step = engine.createStep(stepConfig)
206
- const result = await step.execute(context, engine)
207
- results.push(result)
211
+ const iterationResults = []
212
+ for (const stepConfig of (step.steps || [])) {
213
+ const result = await this.executeStep(stepConfig, context)
214
+ iterationResults.push(result)
208
215
  }
216
+ results.push(iterationResults)
209
217
 
210
218
  // 检查终止条件
211
- if (this.until) {
219
+ if (step.until) {
212
220
  let shouldStop = false
213
- if (typeof this.until === 'function') {
214
- shouldStop = this.until(context)
215
- } else if (typeof this.until === 'string') {
216
- // eslint-disable-next-line no-new-func
217
- const fn = new Function('context', `with(context.variables) { return (${this.until}) }`)
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}) }`)
218
225
  shouldStop = fn(context)
219
226
  }
220
227
 
221
228
  if (shouldStop) {
222
- console.log(`[Workflow] Loop terminated at iteration ${i}`)
229
+ console.log(`[StepExecutor] Loop terminated at iteration ${i}`)
223
230
  break
224
231
  }
225
232
  }
@@ -227,80 +234,89 @@ class LoopStep extends WorkflowStep {
227
234
 
228
235
  return results
229
236
  }
230
- }
231
-
232
- /**
233
- * 延迟步骤
234
- */
235
- class DelayStep extends WorkflowStep {
236
- constructor(config) {
237
- super({ ...config, type: StepType.DELAY })
238
- this.delayMs = config.delayMs || 1000
239
- }
240
237
 
241
- async execute(context, engine) {
242
- console.log(`[Workflow] Delaying ${this.delayMs}ms`)
243
- await new Promise(resolve => setTimeout(resolve, this.delayMs))
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))
244
245
  return null
245
246
  }
246
- }
247
247
 
248
- /**
249
- * 工具步骤
250
- */
251
- class ToolStep extends WorkflowStep {
252
- constructor(config) {
253
- super({ ...config, type: StepType.TOOL })
254
- this.tool = config.tool
255
- this.args = config.args || {}
256
- this.outputVariable = config.outputVariable || null
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)
257
254
  }
258
255
 
259
- async execute(context, engine) {
260
- if (!this.tool) {
261
- throw new Error('Tool step requires a tool name')
262
- }
256
+ /**
257
+ * 执行消息步骤(ExplorerLoop 专用)
258
+ */
259
+ async executeMessage(step, context) {
260
+ console.log(`[StepExecutor] Executing message step`)
263
261
 
264
- console.log(`[Workflow] Executing tool: ${this.tool}`)
262
+ const agent = this._getActiveAgent()
263
+ if (!agent) {
264
+ return { success: false, error: '没有可用的代理' }
265
+ }
265
266
 
266
- // 解析工具参数,支持变量引用
267
- const resolvedArgs = this._resolveArgs(this.args, context)
267
+ let content = step.content || ''
268
+ // 支持变量引用
269
+ content = this._resolveValue(content, context)
268
270
 
269
- // 获取当前 sessionId(从上下文变量或执行上下文)
270
- let sessionId = context.variables._sessionId
271
- if (!sessionId && engine.framework.getExecutionContext) {
272
- const ctx = engine.framework.getExecutionContext()
273
- sessionId = ctx?.sessionId
271
+ // 如果有事件上下文,附加到消息
272
+ if (context.variables?._event) {
273
+ content = `${content}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
274
274
  }
275
275
 
276
- // 使用 sessionId 上下文执行工具
277
- let result
278
- if (sessionId && engine.framework.runWithContext) {
279
- result = await engine.framework.runWithContext(
280
- { sessionId },
281
- async () => await engine.framework.executeTool(this.tool, resolvedArgs)
282
- )
283
- } else {
284
- result = await engine.framework.executeTool(this.tool, resolvedArgs)
285
- }
276
+ const result = await agent.pushMessage(content)
277
+ return { success: true, result }
278
+ }
286
279
 
287
- // 保存结果到变量
288
- if (this.outputVariable) {
289
- context.variables[this.outputVariable] = result
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: '思考插件不可用' }
290
289
  }
291
- context.lastResult = result
292
290
 
293
- // 检查工具执行结果
294
- if (result && result.error) {
295
- console.warn(`[Workflow] Tool ${this.tool} returned error: ${result.error}`)
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
296
  }
297
297
 
298
+ const result = await thinkPlugin._triggerThinking({
299
+ topic,
300
+ mode: step.mode || 'reflect',
301
+ depth: step.depth || 2
302
+ })
303
+
298
304
  return result
299
305
  }
300
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
+
301
318
  /**
302
319
  * 解析参数中的变量引用
303
- * 支持 {{variableName}} 语法
304
320
  */
305
321
  _resolveArgs(args, context) {
306
322
  const resolved = {}
@@ -312,18 +328,14 @@ class ToolStep extends WorkflowStep {
312
328
 
313
329
  _resolveValue(value, context) {
314
330
  if (typeof value === 'string') {
315
- // 替换 {{variable}} 或 {{variables.name}} 语法
316
331
  return value.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
317
- // 支持 variables.xxx 或直接 xxx 格式
318
332
  if (path.startsWith('variables.')) {
319
333
  return this._getNestedValue(context, path) ?? match
320
334
  } else if (path.startsWith('context.')) {
321
335
  return this._getNestedValue(context, path) ?? match
322
336
  } else {
323
- // 尝试从 context.variables 获取
324
337
  const val = this._getNestedValue(context.variables, path)
325
338
  if (val !== undefined) return val
326
- // 尝试从 context 直接获取
327
339
  return this._getNestedValue(context, path) ?? match
328
340
  }
329
341
  })
@@ -351,6 +363,175 @@ class ToolStep extends WorkflowStep {
351
363
  }
352
364
  }
353
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
+ }
439
+ }
440
+
441
+ /**
442
+ * 顺序步骤
443
+ */
444
+ class SequentialStep extends WorkflowStep {
445
+ constructor(config) {
446
+ super({ ...config, type: StepType.SEQUENTIAL })
447
+ this.steps = config.steps || []
448
+ }
449
+
450
+ async execute(context, engine) {
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
457
+ }
458
+ return await executor.executeSequential(stepConfig, context)
459
+ }
460
+ }
461
+
462
+ /**
463
+ * 循环步骤
464
+ */
465
+ class LoopStep extends WorkflowStep {
466
+ constructor(config) {
467
+ super({ ...config, type: StepType.LOOP })
468
+ this.maxIterations = config.maxIterations || 10
469
+ this.loopVariable = config.loopVariable || 'loopIndex'
470
+ this.steps = config.steps || []
471
+ this.until = config.until || null
472
+ }
473
+
474
+ async execute(context, engine) {
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
484
+ }
485
+ return await executor.executeLoop(stepConfig, context)
486
+ }
487
+ }
488
+
489
+ /**
490
+ * 延迟步骤
491
+ */
492
+ class DelayStep extends WorkflowStep {
493
+ constructor(config) {
494
+ super({ ...config, type: StepType.DELAY })
495
+ this.delayMs = config.delayMs || 1000
496
+ }
497
+
498
+ async execute(context, engine) {
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)
532
+ }
533
+ }
534
+
354
535
  /**
355
536
  * 工作流引擎
356
537
  */
@@ -634,6 +815,7 @@ module.exports = {
634
815
  WorkflowEngine,
635
816
  WorkflowStep,
636
817
  StepType,
818
+ StepExecutor,
637
819
  ScriptStep,
638
820
  ConditionStep,
639
821
  SequentialStep,