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.
- package/.claude/settings.local.json +148 -145
- package/examples/basic.js +110 -110
- package/examples/mcp-example.js +53 -53
- package/examples/skill-example.js +49 -49
- package/examples/test-mcp.js +79 -79
- package/examples/test-reload.js +61 -61
- package/news-20260329-1774794949179.html +39 -0
- package/news-20260329-1774794970785.html +39 -0
- package/news-20260329-1774797491928.html +39 -0
- package/package.json +1 -1
- package/plugins/ambient-agent-plugin.js +333 -22
- package/plugins/email.js +106 -20
- package/plugins/feishu-plugin.js +12 -2
- package/plugins/file-system-plugin.js +76 -30
- package/plugins/python-executor-plugin.js +41 -8
- package/plugins/scheduler-plugin.js +14 -11
- package/plugins/telegram-plugin.js +51 -23
- package/plugins/web-plugin.js +8 -6
- package/plugins/weixin-plugin.js +12 -2
- package/skills/ambient-agent/SKILL.md +84 -14
- package/skills/workflow-guide/SKILL.md +214 -2
- package/skills/workflow-troubleshooting/DEBUGGING.md +182 -0
- package/skills/workflow-troubleshooting/SKILL.md +314 -0
- package/src/capabilities/workflow-engine.js +367 -22
- package/src/core/agent-chat.js +106 -14
- package/src/core/framework.js +81 -1
- package/src/executors/executor-base.js +58 -58
- package/test-server.js +0 -25
- package/test.txt +0 -3
|
@@ -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
|
-
|
|
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
|
-
|
|
112
|
-
|
|
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:
|
|
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
|
-
|
|
148
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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: ${
|
|
880
|
+
throw new Error(`Unknown step type: ${type}`)
|
|
585
881
|
}
|
|
586
882
|
|
|
587
|
-
|
|
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:
|
|
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,
|