foliko 1.0.67 → 1.0.69

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.
@@ -16,6 +16,8 @@ const StepType = {
16
16
  AGENT: 'agent',
17
17
  SCRIPT: 'script',
18
18
  CONDITION: 'condition',
19
+ SWITCH: 'switch',
20
+ TRY: 'try',
19
21
  PARALLEL: 'parallel',
20
22
  SEQUENTIAL: 'sequential',
21
23
  LOOP: 'loop',
@@ -24,7 +26,8 @@ const StepType = {
24
26
  INPUT: 'input',
25
27
  OUTPUT: 'output',
26
28
  MESSAGE: 'message',
27
- THINK: 'think'
29
+ THINK: 'think',
30
+ WORKFLOW: 'workflow' // 嵌套工作流
28
31
  }
29
32
 
30
33
  /**
@@ -67,15 +70,117 @@ class StepExecutor {
67
70
  [StepType.TOOL]: this.executeTool,
68
71
  [StepType.SCRIPT]: this.executeScript,
69
72
  [StepType.CONDITION]: this.executeCondition,
73
+ [StepType.SWITCH]: this.executeSwitch,
74
+ [StepType.TRY]: this.executeTry,
75
+ [StepType.PARALLEL]: this.executeParallel,
70
76
  [StepType.LOOP]: this.executeLoop,
71
77
  [StepType.DELAY]: this.executeDelay,
72
78
  [StepType.SEQUENTIAL]: this.executeSequential,
73
79
  [StepType.MESSAGE]: this.executeMessage,
74
- [StepType.THINK]: this.executeThink
80
+ [StepType.THINK]: this.executeThink,
81
+ [StepType.WORKFLOW]: this.executeWorkflowStep
75
82
  }
76
83
  return handlers[type]
77
84
  }
78
85
 
86
+ /**
87
+ * 执行 switch 步骤
88
+ */
89
+ async executeSwitch(step, context) {
90
+ console.log(`[StepExecutor] Executing switch: ${step.name || step.id}`)
91
+
92
+ const value = this._resolveValue(step.value, context)
93
+ const branches = step.branches || []
94
+
95
+ for (const branch of branches) {
96
+ const caseValue = this._resolveValue(branch.case, context)
97
+ if (value === caseValue) {
98
+ console.log(`[StepExecutor] Switch matched case: ${caseValue}`)
99
+ if (branch.steps && branch.steps.length > 0) {
100
+ return await this.executeSteps(branch.steps, context)
101
+ }
102
+ return { matched: caseValue }
103
+ }
104
+ }
105
+
106
+ // 默认分支
107
+ if (step.default && step.default.steps) {
108
+ console.log(`[StepExecutor] Executing switch default branch`)
109
+ return await this.executeSteps(step.default.steps, context)
110
+ }
111
+
112
+ return { matched: null, value }
113
+ }
114
+
115
+ /**
116
+ * 执行 try-catch 步骤
117
+ */
118
+ async executeTry(step, context) {
119
+ console.log(`[StepExecutor] Executing try-catch: ${step.name || step.id}`)
120
+
121
+ try {
122
+ if (step.try && step.try.steps) {
123
+ const result = await this.executeSteps(step.try.steps, context)
124
+ return { success: true, result }
125
+ }
126
+ return { success: true }
127
+ } catch (err) {
128
+ console.log(`[StepExecutor] Try block failed, executing catch: ${err.message}`)
129
+ if (step.catch && step.catch.steps) {
130
+ const catchResult = await this.executeSteps(step.catch.steps, context)
131
+ return { success: false, error: err.message, caught: catchResult }
132
+ }
133
+ return { success: false, error: err.message }
134
+ }
135
+ }
136
+
137
+ /**
138
+ * 执行嵌套工作流步骤
139
+ */
140
+ async executeWorkflowStep(step, context) {
141
+ console.log(`[StepExecutor] Executing nested workflow: ${step.name || step.id}`)
142
+
143
+ if (!step.workflow) {
144
+ throw new Error('Workflow step requires a workflow definition')
145
+ }
146
+
147
+ // 执行嵌套工作流
148
+ const result = await this.framework.pluginManager.get('workflow').executeWorkflow(
149
+ step.workflow,
150
+ step.input || {},
151
+ context.variables._sessionId
152
+ )
153
+
154
+ // 将嵌套工作流的输出合并到当前上下文
155
+ if (result.output) {
156
+ for (const [key, value] of Object.entries(result.output)) {
157
+ context.variables[key] = value
158
+ }
159
+ }
160
+
161
+ return result
162
+ }
163
+
164
+ /**
165
+ * 执行并行步骤
166
+ */
167
+ async executeParallel(step, context) {
168
+ console.log(`[StepExecutor] Executing parallel: ${step.name || step.id}`)
169
+
170
+ const steps = step.steps || []
171
+ if (steps.length === 0) {
172
+ return []
173
+ }
174
+
175
+ // 并行执行所有步骤
176
+ const promises = steps.map(stepConfig => {
177
+ return this.executeStep(stepConfig, context)
178
+ })
179
+
180
+ const results = await Promise.all(promises)
181
+ return results
182
+ }
183
+
79
184
  /**
80
185
  * 执行工具步骤
81
186
  */
@@ -87,7 +192,14 @@ class StepExecutor {
87
192
  console.log(`[StepExecutor] Executing tool: ${step.tool}`)
88
193
 
89
194
  // 解析工具参数,支持变量引用
90
- const resolvedArgs = this._resolveArgs(step.args || {}, context)
195
+ let resolvedArgs = this._resolveArgs(step.args || {}, context)
196
+
197
+ // 兼容旧格式:处理 step.input 字段(${stepId.output} 引用)
198
+ // 将 input 注入到 args.input_data,供 python-execute 使用
199
+ if (step.input) {
200
+ const resolvedInput = this._resolveArgs(step.input, context)
201
+ resolvedArgs.input_data = resolvedInput
202
+ }
91
203
 
92
204
  // 获取当前 sessionId
93
205
  let sessionId = context.variables?._sessionId
@@ -108,8 +220,10 @@ class StepExecutor {
108
220
  }
109
221
 
110
222
  // 保存结果到变量
111
- if (step.outputVariable) {
112
- context.variables[step.outputVariable] = result
223
+ // 支持 output 作为 outputVariable 的别名
224
+ const outputVar = step.outputVariable || step.output
225
+ if (outputVar) {
226
+ context.variables[outputVar] = result
113
227
  }
114
228
  context.lastResult = result
115
229
 
@@ -127,8 +241,15 @@ class StepExecutor {
127
241
  console.log(`[StepExecutor] Executing script step: ${step.name || step.id}`)
128
242
 
129
243
  try {
244
+ // 兼容旧格式:处理 step.input 字段(${stepId.output} 引用)
245
+ let resolvedInput = context.input || {}
246
+ if (step.input && typeof step.input === 'object') {
247
+ resolvedInput = this._resolveArgs(step.input, context)
248
+ }
249
+
130
250
  const scriptContext = {
131
- input: context.input,
251
+ input: resolvedInput,
252
+ input_data: resolvedInput, // 兼容 input_data 变量名
132
253
  variables: context.variables,
133
254
  previousResult: context.lastResult,
134
255
  console: {
@@ -144,8 +265,10 @@ class StepExecutor {
144
265
  result = await fn(scriptContext)
145
266
  }
146
267
 
147
- if (step.outputVariable) {
148
- context.variables[step.outputVariable] = result
268
+ // 支持 output 作为 outputVariable 的别名
269
+ const outputVar = step.outputVariable || step.output
270
+ if (outputVar) {
271
+ context.variables[outputVar] = result
149
272
  }
150
273
  context.lastResult = result
151
274
 
@@ -259,10 +382,11 @@ class StepExecutor {
259
382
  async executeMessage(step, context) {
260
383
  console.log(`[StepExecutor] Executing message step`)
261
384
 
262
- const agent = this._getActiveAgent()
263
- if (!agent) {
264
- return { success: false, error: '没有可用的代理' }
265
- }
385
+ // 使用子Agent处理消息,避免阻塞主agent
386
+ const messageAgent = this.framework.createSubAgent({
387
+ name: 'workflow_message',
388
+ role: '工作流任务执行助手,专注于处理工作流中的消息任务'
389
+ })
266
390
 
267
391
  let content = step.content || ''
268
392
  // 支持变量引用
@@ -273,7 +397,7 @@ class StepExecutor {
273
397
  content = `${content}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
274
398
  }
275
399
 
276
- const result = await agent.pushMessage(content)
400
+ const result = await messageAgent.chat(content)
277
401
  return { success: true, result }
278
402
  }
279
403
 
@@ -334,7 +458,35 @@ class StepExecutor {
334
458
  // {{variables.xxx}} - 显式引用 context.variables
335
459
  // {{context.xxx}} - 显式引用 context 根属性
336
460
  // {{lastResult}} - 上一步结果(result 的别名)
337
- return value.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
461
+ // ${stepId.output} - 引用指定 id 步骤的输出(兼容旧格式)
462
+ // ${stepId.output.path} - 从指定步骤输出提取字段
463
+ let result = value
464
+
465
+ // 先处理 ${stepId.output} 格式(兼容旧格式)
466
+ result = result.replace(/\$\{([^}]+)\}/g, (match, path) => {
467
+ const stepOutputs = context.variables._stepOutputs || {}
468
+ if (path === 'output') {
469
+ // ${output} 等同于 ${stepId.output} 引用上一步
470
+ return context.lastResult ?? match
471
+ }
472
+ if (path.includes('.')) {
473
+ // ${stepId.output.field} 格式
474
+ const [stepId, ...fieldParts] = path.split('.')
475
+ const stepOutput = stepOutputs[stepId]
476
+ if (stepOutput !== undefined) {
477
+ const val = this._getNestedValue(stepOutput, fieldParts.join('.'))
478
+ if (val !== undefined) return val
479
+ }
480
+ } else {
481
+ // ${stepId.output} 格式
482
+ const stepOutput = stepOutputs[path]
483
+ if (stepOutput !== undefined) return stepOutput
484
+ }
485
+ return match
486
+ })
487
+
488
+ // 再处理 {{...}} 格式(支持 _event.email.from 等嵌套属性)
489
+ result = result.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
338
490
  // result 和 lastResult 都指向 context.lastResult
339
491
  if (path === 'result' || path === 'lastResult') {
340
492
  return context.lastResult ?? match
@@ -356,6 +508,8 @@ class StepExecutor {
356
508
  return this._getNestedValue(context, path) ?? match
357
509
  }
358
510
  })
511
+
512
+ return result
359
513
  } else if (Array.isArray(value)) {
360
514
  return value.map(v => this._resolveValue(v, context))
361
515
  } else if (typeof value === 'object' && value !== null) {
@@ -463,6 +617,98 @@ class ConditionStep extends WorkflowStep {
463
617
  }
464
618
  }
465
619
 
620
+ /**
621
+ * 并行步骤
622
+ */
623
+ class ParallelStep extends WorkflowStep {
624
+ constructor(config) {
625
+ super({ ...config, type: StepType.PARALLEL })
626
+ this.steps = config.steps || []
627
+ }
628
+
629
+ async execute(context, engine) {
630
+ const executor = new StepExecutor(engine.framework)
631
+ const stepConfig = {
632
+ id: this.id,
633
+ name: this.name,
634
+ type: StepType.PARALLEL,
635
+ steps: this.steps
636
+ }
637
+ return await executor.executeParallel(stepConfig, context)
638
+ }
639
+ }
640
+
641
+ /**
642
+ * Switch 步骤
643
+ */
644
+ class SwitchStep extends WorkflowStep {
645
+ constructor(config) {
646
+ super({ ...config, type: StepType.SWITCH })
647
+ this.value = config.value
648
+ this.branches = config.branches || []
649
+ this.default = config.default || null
650
+ }
651
+
652
+ async execute(context, engine) {
653
+ const executor = new StepExecutor(engine.framework)
654
+ const stepConfig = {
655
+ id: this.id,
656
+ name: this.name,
657
+ type: StepType.SWITCH,
658
+ value: this.value,
659
+ branches: this.branches,
660
+ default: this.default
661
+ }
662
+ return await executor.executeSwitch(stepConfig, context)
663
+ }
664
+ }
665
+
666
+ /**
667
+ * Try-Catch 步骤
668
+ */
669
+ class TryStep extends WorkflowStep {
670
+ constructor(config) {
671
+ super({ ...config, type: StepType.TRY })
672
+ this.try = config.try || {}
673
+ this.catch = config.catch || {}
674
+ }
675
+
676
+ async execute(context, engine) {
677
+ const executor = new StepExecutor(engine.framework)
678
+ const stepConfig = {
679
+ id: this.id,
680
+ name: this.name,
681
+ type: StepType.TRY,
682
+ try: this.try,
683
+ catch: this.catch
684
+ }
685
+ return await executor.executeTry(stepConfig, context)
686
+ }
687
+ }
688
+
689
+ /**
690
+ * 嵌套工作流步骤
691
+ */
692
+ class NestedWorkflowStep extends WorkflowStep {
693
+ constructor(config) {
694
+ super({ ...config, type: StepType.WORKFLOW })
695
+ this.workflow = config.workflow
696
+ this.input = config.input || {}
697
+ }
698
+
699
+ async execute(context, engine) {
700
+ const executor = new StepExecutor(engine.framework)
701
+ const stepConfig = {
702
+ id: this.id,
703
+ name: this.name,
704
+ type: StepType.WORKFLOW,
705
+ workflow: this.workflow,
706
+ input: this.input
707
+ }
708
+ return await executor.executeWorkflowStep(stepConfig, context)
709
+ }
710
+ }
711
+
466
712
  /**
467
713
  * 顺序步骤
468
714
  */
@@ -541,6 +787,8 @@ class ToolStep extends WorkflowStep {
541
787
  this.tool = config.tool
542
788
  this.args = config.args || {}
543
789
  this.outputVariable = config.outputVariable || null
790
+ this.output = config.output || null // 兼容旧格式
791
+ this.input = config.input || null // 兼容旧格式:input 字段
544
792
  }
545
793
 
546
794
  async execute(context, engine) {
@@ -551,7 +799,9 @@ class ToolStep extends WorkflowStep {
551
799
  type: StepType.TOOL,
552
800
  tool: this.tool,
553
801
  args: this.args,
554
- outputVariable: this.outputVariable
802
+ outputVariable: this.outputVariable,
803
+ output: this.output, // 传递 output
804
+ input: this.input // 传递 input
555
805
  }
556
806
  return await executor.executeTool(stepConfig, context)
557
807
  }
@@ -574,17 +824,64 @@ class WorkflowEngine extends EventEmitter {
574
824
  this._steps.set(type, StepClass)
575
825
  }
576
826
 
577
- /**
827
+ /**
578
828
  * 创建步骤实例
829
+ * 自动推断步骤类型:
830
+ * - 有 tool 字段 -> tool 类型
831
+ * - 有 code/script 字段 -> script 类型
832
+ * - 有 branches 字段 -> condition 类型
833
+ * - 有 value + branches -> switch 类型
834
+ * - 有 try/catch 字段 -> try 类型
835
+ * - 有 parallel 属性 -> parallel 类型
836
+ * - 有 steps 字段 + loopVariable/maxIterations -> loop 类型
837
+ * - 有 steps 字段 -> sequential 类型
838
+ * - 有 delayMs 字段 -> delay 类型
839
+ * - 有 workflow 字段 -> workflow 类型
579
840
  */
580
841
  createStep(config) {
581
- const StepClass = this._steps.get(config.type)
842
+ let type = config.type
843
+
844
+ // 自动推断类型
845
+ if (!type) {
846
+ if (config.tool) {
847
+ type = StepType.TOOL
848
+ } else if (config.code || config.script) {
849
+ type = StepType.SCRIPT
850
+ } else if (config.try || config.catch) {
851
+ type = StepType.TRY
852
+ } else if (config.value !== undefined && config.branches) {
853
+ type = StepType.SWITCH
854
+ } else if (config.parallel === true || config.mode === 'parallel') {
855
+ type = StepType.PARALLEL
856
+ } else if (config.workflow) {
857
+ type = StepType.WORKFLOW
858
+ } else if (config.branches) {
859
+ type = StepType.CONDITION
860
+ } else if (config.steps && (config.loopVariable || config.maxIterations)) {
861
+ type = StepType.LOOP
862
+ } else if (config.steps) {
863
+ type = StepType.SEQUENTIAL
864
+ } else if (config.delayMs !== undefined) {
865
+ type = StepType.DELAY
866
+ } else if (config.message) {
867
+ type = StepType.MESSAGE
868
+ } else if (config.topic) {
869
+ type = StepType.THINK
870
+ }
871
+ }
872
+
873
+ if (!type) {
874
+ throw new Error(`Cannot infer step type for step: ${JSON.stringify(config).substring(0, 100)}`)
875
+ }
876
+
877
+ const StepClass = this._steps.get(type)
582
878
 
583
879
  if (!StepClass) {
584
- throw new Error(`Unknown step type: ${config.type}`)
880
+ throw new Error(`Unknown step type: ${type}`)
585
881
  }
586
882
 
587
- return new StepClass(config)
883
+ // 确保配置有 type 字段
884
+ return new StepClass({ ...config, type })
588
885
  }
589
886
 
590
887
  /**
@@ -626,10 +923,14 @@ class WorkflowPlugin extends Plugin {
626
923
  // 注册内置步骤类型
627
924
  this._engine.registerStepType(StepType.SCRIPT, ScriptStep)
628
925
  this._engine.registerStepType(StepType.CONDITION, ConditionStep)
926
+ this._engine.registerStepType(StepType.SWITCH, SwitchStep)
927
+ this._engine.registerStepType(StepType.TRY, TryStep)
928
+ this._engine.registerStepType(StepType.PARALLEL, ParallelStep)
629
929
  this._engine.registerStepType(StepType.SEQUENTIAL, SequentialStep)
630
930
  this._engine.registerStepType(StepType.LOOP, LoopStep)
631
931
  this._engine.registerStepType(StepType.DELAY, DelayStep)
632
932
  this._engine.registerStepType(StepType.TOOL, ToolStep)
933
+ this._engine.registerStepType(StepType.WORKFLOW, NestedWorkflowStep)
633
934
 
634
935
  // 注册工作流执行工具
635
936
  framework.registerTool({
@@ -714,7 +1015,7 @@ class WorkflowPlugin extends Plugin {
714
1015
 
715
1016
  if (workflowDef && workflowDef.steps) {
716
1017
  this._workflows.set(workflowName, workflowDef)
717
- console.log(`[Workflow] Loaded: ${workflowName}`)
1018
+ //console.log(`[Workflow] Loaded: ${workflowName}`)
718
1019
  }
719
1020
  } catch (err) {
720
1021
  console.error(`[Workflow] Failed to load ${file}:`, err.message)
@@ -758,6 +1059,21 @@ class WorkflowPlugin extends Plugin {
758
1059
  console.log('[Workflow] Reloading...')
759
1060
  this._framework = framework
760
1061
 
1062
+ // 重新创建 engine(确保使用最新代码)
1063
+ this._engine = new (require('./src/capabilities/workflow-engine').WorkflowEngine)(framework)
1064
+
1065
+ // 注册内置步骤类型
1066
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.SCRIPT, require('./src/capabilities/workflow-engine').ScriptStep)
1067
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.TOOL, require('./src/capabilities/workflow-engine').ToolStep)
1068
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.CONDITION, require('./src/capabilities/workflow-engine').ConditionStep)
1069
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.SWITCH, require('./src/capabilities/workflow-engine').SwitchStep)
1070
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.TRY, require('./src/capabilities/workflow-engine').TryStep)
1071
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.PARALLEL, require('./src/capabilities/workflow-engine').ParallelStep)
1072
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.SEQUENTIAL, require('./src/capabilities/workflow-engine').SequentialStep)
1073
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.LOOP, require('./src/capabilities/workflow-engine').LoopStep)
1074
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.DELAY, require('./src/capabilities/workflow-engine').DelayStep)
1075
+ this._engine.registerStepType(require('./src/capabilities/workflow-engine').StepType.WORKFLOW, require('./src/capabilities/workflow-engine').NestedWorkflowStep)
1076
+
761
1077
  // 清除已注册的工具
762
1078
  for (const toolName of this._workflowTools.values()) {
763
1079
  // 工具注销需要框架支持,这里只清理内部状态
@@ -808,15 +1124,40 @@ class WorkflowPlugin extends Plugin {
808
1124
  // 执行工作流步骤
809
1125
  if (workflow.steps && Array.isArray(workflow.steps)) {
810
1126
  const results = []
1127
+ // 按 id 存储步骤输出,供 ${id.output} 引用
1128
+ context.variables._stepOutputs = {}
811
1129
  for (const stepConfig of workflow.steps) {
812
1130
  const step = this._engine.createStep(stepConfig)
813
1131
  const result = await step.execute(context, this._engine)
814
1132
  results.push(result)
1133
+ // 如果步骤有 id,存储其输出
1134
+ if (stepConfig.id) {
1135
+ context.variables._stepOutputs[stepConfig.id] = result
1136
+ }
1137
+ }
1138
+
1139
+ // 只返回最后一步的结果(包含最终输出)和成功状态
1140
+ // 不返回所有中间结果,避免上下文超限
1141
+ const lastResult = results.length > 0 ? results[results.length - 1] : null
1142
+
1143
+ // 从 context.variables 中提取非下划线开头的用户变量
1144
+ // 下划线开头的是内部变量(如 _stepOutputs),不需要返回
1145
+ const userVariables = {}
1146
+ for (const [key, value] of Object.entries(context.variables)) {
1147
+ if (!key.startsWith('_')) {
1148
+ userVariables[key] = value
1149
+ }
1150
+ }
1151
+
1152
+ return {
1153
+ success: true,
1154
+ stepCount: workflow.steps.length,
1155
+ result: lastResult,
1156
+ output: userVariables
815
1157
  }
816
- return { success: true, results, output: context.variables }
817
1158
  }
818
1159
 
819
- return { success: true, output: context.variables }
1160
+ return { success: true, output: {} }
820
1161
  } catch (err) {
821
1162
  return { success: false, error: err.message }
822
1163
  }
@@ -843,6 +1184,10 @@ module.exports = {
843
1184
  StepExecutor,
844
1185
  ScriptStep,
845
1186
  ConditionStep,
1187
+ ParallelStep,
1188
+ SwitchStep,
1189
+ TryStep,
1190
+ NestedWorkflowStep,
846
1191
  SequentialStep,
847
1192
  LoopStep,
848
1193
  DelayStep,