foliko 1.0.65 → 1.0.67
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/package.json +1 -1
- package/plugins/ambient-agent-plugin.js +158 -46
- package/plugins/email.js +36 -4
- package/skills/ambient-agent/SKILL.md +234 -0
- package/skills/workflow-guide/SKILL.md +74 -14
- package/src/capabilities/workflow-engine.js +388 -181
- package/src/core/agent-chat.js +26 -4
|
@@ -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
|
|
32
|
-
constructor(
|
|
33
|
-
this.
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
59
|
+
return results
|
|
53
60
|
}
|
|
54
|
-
}
|
|
55
61
|
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
67
|
-
|
|
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:${
|
|
135
|
+
log: (...args) => console.log(`[Script:${step.id}]`, ...args)
|
|
77
136
|
}
|
|
78
137
|
}
|
|
79
138
|
|
|
80
|
-
// 执行脚本
|
|
81
139
|
let result
|
|
82
|
-
if (typeof
|
|
83
|
-
result = await
|
|
84
|
-
} else if (typeof
|
|
85
|
-
|
|
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
|
-
|
|
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
157
|
|
|
103
|
-
/**
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
super({ ...config, type: StepType.CONDITION })
|
|
109
|
-
this.branches = config.branches || []
|
|
110
|
-
this.defaultBranch = config.defaultBranch || null
|
|
111
|
-
}
|
|
112
|
-
|
|
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
|
|
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(`[
|
|
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(`[
|
|
184
|
+
console.warn(`[StepExecutor] Branch condition error:`, err.message)
|
|
142
185
|
}
|
|
143
186
|
}
|
|
144
187
|
|
|
145
188
|
// 执行默认分支
|
|
146
|
-
if (
|
|
147
|
-
console.log(`[
|
|
148
|
-
|
|
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
|
-
|
|
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
196
|
|
|
194
|
-
|
|
195
|
-
|
|
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 <
|
|
200
|
-
context.variables[
|
|
207
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
208
|
+
context.variables[loopVariable] = i
|
|
209
|
+
console.log(`[StepExecutor] Loop iteration ${i}`)
|
|
201
210
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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 (
|
|
219
|
+
if (step.until) {
|
|
212
220
|
let shouldStop = false
|
|
213
|
-
if (typeof
|
|
214
|
-
shouldStop =
|
|
215
|
-
} else if (typeof
|
|
216
|
-
|
|
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(`[
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
256
|
+
/**
|
|
257
|
+
* 执行消息步骤(ExplorerLoop 专用)
|
|
258
|
+
*/
|
|
259
|
+
async executeMessage(step, context) {
|
|
260
|
+
console.log(`[StepExecutor] Executing message step`)
|
|
263
261
|
|
|
264
|
-
|
|
262
|
+
const agent = this._getActiveAgent()
|
|
263
|
+
if (!agent) {
|
|
264
|
+
return { success: false, error: '没有可用的代理' }
|
|
265
|
+
}
|
|
265
266
|
|
|
266
|
-
|
|
267
|
-
|
|
267
|
+
let content = step.content || ''
|
|
268
|
+
// 支持变量引用
|
|
269
|
+
content = this._resolveValue(content, context)
|
|
268
270
|
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
-
|
|
289
|
-
|
|
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
|
-
|
|
295
|
-
|
|
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,31 @@ class ToolStep extends WorkflowStep {
|
|
|
312
328
|
|
|
313
329
|
_resolveValue(value, context) {
|
|
314
330
|
if (typeof value === 'string') {
|
|
315
|
-
//
|
|
331
|
+
// 支持多种引用格式:
|
|
332
|
+
// {{result}} - 上一步结果 (lastResult)
|
|
333
|
+
// {{result.body.ip}} - 从上一步结果提取嵌套字段
|
|
334
|
+
// {{variables.xxx}} - 显式引用 context.variables
|
|
335
|
+
// {{context.xxx}} - 显式引用 context 根属性
|
|
336
|
+
// {{lastResult}} - 上一步结果(result 的别名)
|
|
316
337
|
return value.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
|
|
317
|
-
//
|
|
338
|
+
// result 和 lastResult 都指向 context.lastResult
|
|
339
|
+
if (path === 'result' || path === 'lastResult') {
|
|
340
|
+
return context.lastResult ?? match
|
|
341
|
+
}
|
|
342
|
+
if (path.startsWith('result.') || path.startsWith('lastResult.')) {
|
|
343
|
+
const nestedPath = path.replace(/^(result|lastResult)\./, '')
|
|
344
|
+
const val = this._getNestedValue(context.lastResult, nestedPath)
|
|
345
|
+
if (val !== undefined) return val
|
|
346
|
+
return match
|
|
347
|
+
}
|
|
318
348
|
if (path.startsWith('variables.')) {
|
|
319
349
|
return this._getNestedValue(context, path) ?? match
|
|
320
350
|
} else if (path.startsWith('context.')) {
|
|
321
351
|
return this._getNestedValue(context, path) ?? match
|
|
322
352
|
} else {
|
|
323
|
-
//
|
|
353
|
+
// 先从 variables 查找,再从 context 根属性查找
|
|
324
354
|
const val = this._getNestedValue(context.variables, path)
|
|
325
355
|
if (val !== undefined) return val
|
|
326
|
-
// 尝试从 context 直接获取
|
|
327
356
|
return this._getNestedValue(context, path) ?? match
|
|
328
357
|
}
|
|
329
358
|
})
|
|
@@ -345,12 +374,189 @@ class ToolStep extends WorkflowStep {
|
|
|
345
374
|
let current = obj
|
|
346
375
|
for (const part of parts) {
|
|
347
376
|
if (current === null || current === undefined) return undefined
|
|
377
|
+
// 如果当前值是字符串,尝试解析为 JSON
|
|
378
|
+
if (typeof current === 'string' && part !== '0' && part !== 'length') {
|
|
379
|
+
try {
|
|
380
|
+
current = JSON.parse(current)
|
|
381
|
+
} catch {
|
|
382
|
+
// 解析失败,继续用原值
|
|
383
|
+
}
|
|
384
|
+
}
|
|
348
385
|
current = current[part]
|
|
349
386
|
}
|
|
350
387
|
return current
|
|
351
388
|
}
|
|
352
389
|
}
|
|
353
390
|
|
|
391
|
+
/**
|
|
392
|
+
* 工作流步骤基类
|
|
393
|
+
*/
|
|
394
|
+
class WorkflowStep {
|
|
395
|
+
constructor(config) {
|
|
396
|
+
this.id = config.id || `step_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
397
|
+
this.type = config.type
|
|
398
|
+
this.name = config.name || ''
|
|
399
|
+
this.description = config.description || ''
|
|
400
|
+
this.condition = config.condition || null
|
|
401
|
+
this.timeout = config.timeout || 30000
|
|
402
|
+
this.retry = config.retry || { enabled: false, maxAttempts: 3, delay: 1000 }
|
|
403
|
+
this.onSuccess = config.onSuccess || null
|
|
404
|
+
this.onFailure = config.onFailure || null
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async execute(context, engine) {
|
|
408
|
+
throw new Error('execute() must be implemented by subclass')
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
validate() {
|
|
412
|
+
if (!this.type) {
|
|
413
|
+
throw new Error('Step must have a type')
|
|
414
|
+
}
|
|
415
|
+
return true
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* 脚本步骤
|
|
421
|
+
*/
|
|
422
|
+
class ScriptStep extends WorkflowStep {
|
|
423
|
+
constructor(config) {
|
|
424
|
+
super({ ...config, type: StepType.SCRIPT })
|
|
425
|
+
this.script = config.script
|
|
426
|
+
this.outputVariable = config.outputVariable || null
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async execute(context, engine) {
|
|
430
|
+
// 使用 StepExecutor 执行脚本逻辑
|
|
431
|
+
const executor = new StepExecutor(engine.framework)
|
|
432
|
+
const stepConfig = {
|
|
433
|
+
id: this.id,
|
|
434
|
+
name: this.name,
|
|
435
|
+
type: StepType.SCRIPT,
|
|
436
|
+
script: this.script,
|
|
437
|
+
outputVariable: this.outputVariable
|
|
438
|
+
}
|
|
439
|
+
return await executor.executeScript(stepConfig, context)
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* 条件步骤
|
|
445
|
+
*/
|
|
446
|
+
class ConditionStep extends WorkflowStep {
|
|
447
|
+
constructor(config) {
|
|
448
|
+
super({ ...config, type: StepType.CONDITION })
|
|
449
|
+
this.branches = config.branches || []
|
|
450
|
+
this.defaultBranch = config.defaultBranch || null
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async execute(context, engine) {
|
|
454
|
+
const executor = new StepExecutor(engine.framework)
|
|
455
|
+
const stepConfig = {
|
|
456
|
+
id: this.id,
|
|
457
|
+
name: this.name,
|
|
458
|
+
type: StepType.CONDITION,
|
|
459
|
+
branches: this.branches,
|
|
460
|
+
defaultBranch: this.defaultBranch
|
|
461
|
+
}
|
|
462
|
+
return await executor.executeCondition(stepConfig, context)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* 顺序步骤
|
|
468
|
+
*/
|
|
469
|
+
class SequentialStep extends WorkflowStep {
|
|
470
|
+
constructor(config) {
|
|
471
|
+
super({ ...config, type: StepType.SEQUENTIAL })
|
|
472
|
+
this.steps = config.steps || []
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
async execute(context, engine) {
|
|
476
|
+
const executor = new StepExecutor(engine.framework)
|
|
477
|
+
const stepConfig = {
|
|
478
|
+
id: this.id,
|
|
479
|
+
name: this.name,
|
|
480
|
+
type: StepType.SEQUENTIAL,
|
|
481
|
+
steps: this.steps
|
|
482
|
+
}
|
|
483
|
+
return await executor.executeSequential(stepConfig, context)
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* 循环步骤
|
|
489
|
+
*/
|
|
490
|
+
class LoopStep extends WorkflowStep {
|
|
491
|
+
constructor(config) {
|
|
492
|
+
super({ ...config, type: StepType.LOOP })
|
|
493
|
+
this.maxIterations = config.maxIterations || 10
|
|
494
|
+
this.loopVariable = config.loopVariable || 'loopIndex'
|
|
495
|
+
this.steps = config.steps || []
|
|
496
|
+
this.until = config.until || null
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async execute(context, engine) {
|
|
500
|
+
const executor = new StepExecutor(engine.framework)
|
|
501
|
+
const stepConfig = {
|
|
502
|
+
id: this.id,
|
|
503
|
+
name: this.name,
|
|
504
|
+
type: StepType.LOOP,
|
|
505
|
+
maxIterations: this.maxIterations,
|
|
506
|
+
loopVariable: this.loopVariable,
|
|
507
|
+
steps: this.steps,
|
|
508
|
+
until: this.until
|
|
509
|
+
}
|
|
510
|
+
return await executor.executeLoop(stepConfig, context)
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* 延迟步骤
|
|
516
|
+
*/
|
|
517
|
+
class DelayStep extends WorkflowStep {
|
|
518
|
+
constructor(config) {
|
|
519
|
+
super({ ...config, type: StepType.DELAY })
|
|
520
|
+
this.delayMs = config.delayMs || 1000
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async execute(context, engine) {
|
|
524
|
+
const executor = new StepExecutor(engine.framework)
|
|
525
|
+
const stepConfig = {
|
|
526
|
+
id: this.id,
|
|
527
|
+
name: this.name,
|
|
528
|
+
type: StepType.DELAY,
|
|
529
|
+
delayMs: this.delayMs
|
|
530
|
+
}
|
|
531
|
+
return await executor.executeDelay(stepConfig, context)
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* 工具步骤
|
|
537
|
+
*/
|
|
538
|
+
class ToolStep extends WorkflowStep {
|
|
539
|
+
constructor(config) {
|
|
540
|
+
super({ ...config, type: StepType.TOOL })
|
|
541
|
+
this.tool = config.tool
|
|
542
|
+
this.args = config.args || {}
|
|
543
|
+
this.outputVariable = config.outputVariable || null
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
async execute(context, engine) {
|
|
547
|
+
const executor = new StepExecutor(engine.framework)
|
|
548
|
+
const stepConfig = {
|
|
549
|
+
id: this.id,
|
|
550
|
+
name: this.name,
|
|
551
|
+
type: StepType.TOOL,
|
|
552
|
+
tool: this.tool,
|
|
553
|
+
args: this.args,
|
|
554
|
+
outputVariable: this.outputVariable
|
|
555
|
+
}
|
|
556
|
+
return await executor.executeTool(stepConfig, context)
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
354
560
|
/**
|
|
355
561
|
* 工作流引擎
|
|
356
562
|
*/
|
|
@@ -634,6 +840,7 @@ module.exports = {
|
|
|
634
840
|
WorkflowEngine,
|
|
635
841
|
WorkflowStep,
|
|
636
842
|
StepType,
|
|
843
|
+
StepExecutor,
|
|
637
844
|
ScriptStep,
|
|
638
845
|
ConditionStep,
|
|
639
846
|
SequentialStep,
|