foliko 1.0.74 → 1.0.76

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.
Files changed (238) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +29 -0
  39. package/.agent/data/plugins-state.json +255 -0
  40. package/.agent/mcp_config.json +4 -0
  41. package/.agent/mcp_config_updated.json +12 -0
  42. package/.agent/plugins.json +5 -0
  43. package/.agent/rules/GEMINI.md +273 -0
  44. package/.agent/rules/allow-rule.md +77 -0
  45. package/.agent/rules/log-rule.md +83 -0
  46. package/.agent/rules/security-rule.md +93 -0
  47. package/.agent/scripts/auto_preview.py +148 -0
  48. package/.agent/scripts/checklist.py +217 -0
  49. package/.agent/scripts/session_manager.py +120 -0
  50. package/.agent/scripts/verify_all.py +327 -0
  51. package/.agent/skills/api-patterns/SKILL.md +81 -0
  52. package/.agent/skills/api-patterns/api-style.md +42 -0
  53. package/.agent/skills/api-patterns/auth.md +24 -0
  54. package/.agent/skills/api-patterns/documentation.md +26 -0
  55. package/.agent/skills/api-patterns/graphql.md +41 -0
  56. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  57. package/.agent/skills/api-patterns/response.md +37 -0
  58. package/.agent/skills/api-patterns/rest.md +40 -0
  59. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  60. package/.agent/skills/api-patterns/security-testing.md +122 -0
  61. package/.agent/skills/api-patterns/trpc.md +41 -0
  62. package/.agent/skills/api-patterns/versioning.md +22 -0
  63. package/.agent/skills/app-builder/SKILL.md +75 -0
  64. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  65. package/.agent/skills/app-builder/feature-building.md +53 -0
  66. package/.agent/skills/app-builder/project-detection.md +34 -0
  67. package/.agent/skills/app-builder/scaffolding.md +118 -0
  68. package/.agent/skills/app-builder/tech-stack.md +40 -0
  69. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  70. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  71. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  72. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  73. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  74. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  75. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  76. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  77. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  78. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  79. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  80. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  81. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  82. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  83. package/.agent/skills/architecture/SKILL.md +55 -0
  84. package/.agent/skills/architecture/context-discovery.md +43 -0
  85. package/.agent/skills/architecture/examples.md +94 -0
  86. package/.agent/skills/architecture/pattern-selection.md +68 -0
  87. package/.agent/skills/architecture/patterns-reference.md +50 -0
  88. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  89. package/.agent/skills/clean-code/SKILL.md +201 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/frontend-design/SKILL.md +418 -0
  92. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  93. package/.agent/skills/frontend-design/color-system.md +311 -0
  94. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  95. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  96. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  97. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  98. package/.agent/skills/frontend-design/typography-system.md +345 -0
  99. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  100. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  101. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  102. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  103. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  104. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  105. package/.agent/workflows/brainstorm.md +113 -0
  106. package/.agent/workflows/create.md +59 -0
  107. package/.agent/workflows/debug.md +103 -0
  108. package/.agent/workflows/deploy.md +176 -0
  109. package/.agent/workflows/enhance.md +63 -0
  110. package/.agent/workflows/orchestrate.md +237 -0
  111. package/.agent/workflows/plan.md +89 -0
  112. package/.agent/workflows/preview.md +81 -0
  113. package/.agent/workflows/simple-test.md +42 -0
  114. package/.agent/workflows/status.md +86 -0
  115. package/.agent/workflows/structured-orchestrate.md +180 -0
  116. package/.agent/workflows/test.md +144 -0
  117. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  118. package/.claude/settings.local.json +11 -1
  119. package/.editorconfig +56 -0
  120. package/.husky/pre-commit +4 -0
  121. package/.lintstagedrc +7 -0
  122. package/.prettierignore +29 -0
  123. package/.prettierrc +11 -0
  124. package/CLAUDE.md +2 -0
  125. package/README.md +64 -55
  126. package/SPEC.md +102 -61
  127. package/cli/bin/foliko.js +11 -11
  128. package/cli/src/commands/chat.js +143 -141
  129. package/cli/src/commands/list.js +93 -90
  130. package/cli/src/index.js +75 -75
  131. package/cli/src/ui/chat-ui.js +201 -199
  132. package/cli/src/utils/ansi.js +40 -40
  133. package/cli/src/utils/markdown.js +292 -296
  134. package/docker-compose.yml +1 -1
  135. package/docs/ai-sdk-optimization.md +655 -643
  136. package/docs/features.md +80 -80
  137. package/docs/quick-reference.md +49 -46
  138. package/docs/user-manual.md +411 -380
  139. package/examples/ambient-example.js +194 -196
  140. package/examples/basic.js +50 -45
  141. package/examples/bootstrap.js +121 -112
  142. package/examples/mcp-example.js +19 -16
  143. package/examples/skill-example.js +20 -20
  144. package/examples/test-chat.js +137 -135
  145. package/examples/test-mcp.js +85 -79
  146. package/examples/test-reload.js +59 -61
  147. package/examples/test-telegram.js +50 -50
  148. package/examples/test-tg-bot.js +45 -42
  149. package/examples/test-tg-simple.js +47 -46
  150. package/examples/test-tg.js +62 -62
  151. package/examples/test-think.js +43 -37
  152. package/examples/test-web-plugin.js +103 -98
  153. package/examples/test-weixin-feishu.js +103 -100
  154. package/examples/workflow.js +158 -158
  155. package/package.json +37 -3
  156. package/plugins/ai-plugin.js +102 -100
  157. package/plugins/ambient-agent/EventWatcher.js +113 -0
  158. package/plugins/ambient-agent/ExplorerLoop.js +640 -0
  159. package/plugins/ambient-agent/GoalManager.js +197 -0
  160. package/plugins/ambient-agent/Reflector.js +95 -0
  161. package/plugins/ambient-agent/StateStore.js +90 -0
  162. package/plugins/ambient-agent/constants.js +101 -0
  163. package/plugins/ambient-agent/index.js +579 -0
  164. package/plugins/audit-plugin.js +187 -187
  165. package/plugins/default-plugins.js +662 -649
  166. package/plugins/email/constants.js +64 -0
  167. package/plugins/email/handlers.js +461 -0
  168. package/plugins/email/index.js +278 -0
  169. package/plugins/email/monitor.js +269 -0
  170. package/plugins/email/parser.js +138 -0
  171. package/plugins/email/reply.js +151 -0
  172. package/plugins/email/utils.js +124 -0
  173. package/plugins/feishu-plugin.js +481 -477
  174. package/plugins/file-system-plugin.js +826 -476
  175. package/plugins/install-plugin.js +199 -197
  176. package/plugins/python-executor-plugin.js +367 -365
  177. package/plugins/python-plugin-loader.js +481 -479
  178. package/plugins/rules-plugin.js +294 -292
  179. package/plugins/scheduler-plugin.js +691 -689
  180. package/plugins/session-plugin.js +369 -367
  181. package/plugins/shell-executor-plugin.js +197 -197
  182. package/plugins/storage-plugin.js +240 -238
  183. package/plugins/subagent-plugin.js +845 -785
  184. package/plugins/telegram-plugin.js +482 -475
  185. package/plugins/think-plugin.js +345 -343
  186. package/plugins/tools-plugin.js +196 -194
  187. package/plugins/web-plugin.js +606 -604
  188. package/plugins/weixin-plugin.js +545 -538
  189. package/reports/system-health-report-20260401.md +79 -0
  190. package/skills/ambient-agent/SKILL.md +49 -39
  191. package/skills/foliko-dev/AGENTS.md +64 -61
  192. package/skills/foliko-dev/SKILL.md +125 -119
  193. package/skills/mcp-usage/SKILL.md +19 -17
  194. package/skills/python-plugin-dev/SKILL.md +16 -15
  195. package/skills/skill-guide/SKILL.md +12 -12
  196. package/skills/subagent-guide/SKILL.md +237 -0
  197. package/skills/workflow-guide/SKILL.md +90 -45
  198. package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
  199. package/skills/workflow-troubleshooting/SKILL.md +156 -79
  200. package/src/capabilities/index.js +11 -11
  201. package/src/capabilities/skill-manager.js +609 -595
  202. package/src/capabilities/workflow-engine.js +1109 -1195
  203. package/src/core/agent-chat.js +882 -735
  204. package/src/core/agent.js +892 -688
  205. package/src/core/framework.js +465 -431
  206. package/src/core/index.js +19 -19
  207. package/src/core/plugin-base.js +219 -219
  208. package/src/core/plugin-manager.js +863 -767
  209. package/src/core/provider.js +114 -111
  210. package/src/core/sub-agent-config.js +264 -0
  211. package/src/core/system-prompt-builder.js +120 -0
  212. package/src/core/tool-registry.js +517 -134
  213. package/src/core/tool-router.js +297 -216
  214. package/src/executors/executor-base.js +12 -12
  215. package/src/executors/mcp-executor.js +741 -729
  216. package/src/index.js +25 -37
  217. package/src/utils/circuit-breaker.js +301 -0
  218. package/src/utils/error-boundary.js +363 -0
  219. package/src/utils/error.js +374 -0
  220. package/src/utils/event-emitter.js +97 -97
  221. package/src/utils/id.js +133 -0
  222. package/src/utils/index.js +217 -3
  223. package/src/utils/logger.js +181 -0
  224. package/src/utils/plugin-helpers.js +90 -0
  225. package/src/utils/retry.js +122 -0
  226. package/src/utils/sandbox.js +292 -0
  227. package/test/tool-registry-validation.test.js +218 -0
  228. package/test_report.md +70 -0
  229. package/website/docs/api.html +169 -107
  230. package/website/docs/configuration.html +296 -144
  231. package/website/docs/plugin-development.html +154 -85
  232. package/website/docs/project-structure.html +110 -109
  233. package/website/docs/skill-development.html +117 -61
  234. package/website/index.html +209 -205
  235. package/website/script.js +136 -133
  236. package/website/styles.css +1 -1
  237. package/plugins/ambient-agent-plugin.js +0 -1565
  238. package/plugins/email.js +0 -1142
@@ -1,1195 +1,1109 @@
1
- /**
2
- * WorkflowEngine 工作流引擎
3
- * 支持结构化工作流定义和执行
4
- */
5
-
6
- const { EventEmitter } = require('../utils/event-emitter')
7
- const { Plugin } = require('../core/plugin-base')
8
- const { z } = require('zod')
9
- const fs = require('fs')
10
- const path = require('path')
11
-
12
- /**
13
- * 工作流步骤类型
14
- */
15
- const StepType = {
16
- AGENT: 'agent',
17
- SCRIPT: 'script',
18
- CONDITION: 'condition',
19
- SWITCH: 'switch',
20
- TRY: 'try',
21
- PARALLEL: 'parallel',
22
- SEQUENTIAL: 'sequential',
23
- LOOP: 'loop',
24
- DELAY: 'delay',
25
- TOOL: 'tool',
26
- INPUT: 'input',
27
- OUTPUT: 'output',
28
- MESSAGE: 'message',
29
- THINK: 'think',
30
- WORKFLOW: 'workflow' // 嵌套工作流
31
- }
32
-
33
- /**
34
- * StepExecutor - 统一的步骤执行器
35
- * 同时被 WorkflowEngine 和 ExplorerLoop 使用
36
- */
37
- class StepExecutor {
38
- constructor(framework) {
39
- this.framework = framework
40
- }
41
-
42
- /**
43
- * 执行单个步骤
44
- */
45
- async executeStep(step, context) {
46
- const handler = this._getStepHandler(step.type)
47
- if (!handler) {
48
- throw new Error(`Unknown step type: ${step.type}`)
49
- }
50
- return await handler.call(this, step, context)
51
- }
52
-
53
- /**
54
- * 执行多个步骤(顺序)
55
- */
56
- async executeSteps(steps, context) {
57
- const results = []
58
- for (const step of steps) {
59
- const result = await this.executeStep(step, context)
60
- results.push(result)
61
- }
62
- return results
63
- }
64
-
65
- /**
66
- * 获取步骤类型处理器
67
- */
68
- _getStepHandler(type) {
69
- const handlers = {
70
- [StepType.TOOL]: this.executeTool,
71
- [StepType.SCRIPT]: this.executeScript,
72
- [StepType.CONDITION]: this.executeCondition,
73
- [StepType.SWITCH]: this.executeSwitch,
74
- [StepType.TRY]: this.executeTry,
75
- [StepType.PARALLEL]: this.executeParallel,
76
- [StepType.LOOP]: this.executeLoop,
77
- [StepType.DELAY]: this.executeDelay,
78
- [StepType.SEQUENTIAL]: this.executeSequential,
79
- [StepType.MESSAGE]: this.executeMessage,
80
- [StepType.THINK]: this.executeThink,
81
- [StepType.WORKFLOW]: this.executeWorkflowStep
82
- }
83
- return handlers[type]
84
- }
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
-
184
- /**
185
- * 执行工具步骤
186
- */
187
- async executeTool(step, context) {
188
- if (!step.tool) {
189
- throw new Error('Tool step requires a tool name')
190
- }
191
-
192
- console.log(`[StepExecutor] Executing tool: ${step.tool}`)
193
-
194
- // 解析工具参数,支持变量引用
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
- }
203
-
204
- // 获取当前 sessionId
205
- let sessionId = context.variables?._sessionId
206
- if (!sessionId && this.framework.getExecutionContext) {
207
- const ctx = this.framework.getExecutionContext()
208
- sessionId = ctx?.sessionId
209
- }
210
-
211
- // 执行工具
212
- let result
213
- if (sessionId && this.framework.runWithContext) {
214
- result = await this.framework.runWithContext(
215
- { sessionId },
216
- async () => await this.framework.executeTool(step.tool, resolvedArgs)
217
- )
218
- } else {
219
- result = await this.framework.executeTool(step.tool, resolvedArgs)
220
- }
221
-
222
- // 保存结果到变量
223
- // 支持 output 作为 outputVariable 的别名
224
- const outputVar = step.outputVariable || step.output
225
- if (outputVar) {
226
- context.variables[outputVar] = result
227
- }
228
- context.lastResult = result
229
-
230
- if (result && result.error) {
231
- console.warn(`[StepExecutor] Tool ${step.tool} returned error: ${result.error}`)
232
- }
233
-
234
- return result
235
- }
236
-
237
- /**
238
- * 执行脚本步骤
239
- */
240
- async executeScript(step, context) {
241
- console.log(`[StepExecutor] Executing script step: ${step.name || step.id}`)
242
-
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
-
250
- const scriptContext = {
251
- input: resolvedInput,
252
- input_data: resolvedInput, // 兼容 input_data 变量名
253
- variables: context.variables,
254
- previousResult: context.lastResult,
255
- console: {
256
- log: (...args) => console.log(`[Script:${step.id}]`, ...args)
257
- }
258
- }
259
-
260
- let result
261
- if (typeof step.script === 'function') {
262
- result = await step.script(scriptContext)
263
- } else if (typeof step.script === 'string') {
264
- const fn = new Function('context', `return (async () => { ${step.script} })()`)
265
- result = await fn(scriptContext)
266
- }
267
-
268
- // 支持 output 作为 outputVariable 的别名
269
- const outputVar = step.outputVariable || step.output
270
- if (outputVar) {
271
- context.variables[outputVar] = result
272
- }
273
- context.lastResult = result
274
-
275
- return result
276
- } catch (err) {
277
- throw new Error(`Script execution failed: ${err.message}`)
278
- }
279
- }
280
-
281
- /**
282
- * 执行条件步骤
283
- */
284
- async executeCondition(step, context) {
285
- console.log(`[StepExecutor] Evaluating condition: ${step.name || step.id}`)
286
-
287
- for (const branch of (step.branches || [])) {
288
- try {
289
- let conditionValue
290
- if (typeof branch.condition === 'function') {
291
- conditionValue = branch.condition(context)
292
- } else if (typeof branch.condition === 'string') {
293
- const fn = new Function('context', `with(context.variables) { return (${branch.condition}) }`)
294
- conditionValue = fn(context)
295
- }
296
-
297
- if (conditionValue) {
298
- console.log(`[StepExecutor] Condition matched: ${branch.name || branch.stepId}`)
299
-
300
- if (branch.steps && branch.steps.length > 0) {
301
- await this.executeSteps(branch.steps, context)
302
- }
303
-
304
- return branch.stepId || branch.name
305
- }
306
- } catch (err) {
307
- console.warn(`[StepExecutor] Branch condition error:`, err.message)
308
- }
309
- }
310
-
311
- // 执行默认分支
312
- if (step.defaultBranch && step.defaultBranch.steps) {
313
- console.log(`[StepExecutor] Executing default branch`)
314
- await this.executeSteps(step.defaultBranch.steps, context)
315
- }
316
-
317
- return null
318
- }
319
-
320
- /**
321
- * 执行循环步骤
322
- */
323
- async executeLoop(step, context) {
324
- console.log(`[StepExecutor] Executing loop: ${step.name || step.id}`)
325
-
326
- const results = []
327
- const maxIterations = step.maxIterations || 10
328
- const loopVariable = step.loopVariable || 'loopIndex'
329
-
330
- for (let i = 0; i < maxIterations; i++) {
331
- context.variables[loopVariable] = i
332
- console.log(`[StepExecutor] Loop iteration ${i}`)
333
-
334
- const iterationResults = []
335
- for (const stepConfig of (step.steps || [])) {
336
- const result = await this.executeStep(stepConfig, context)
337
- iterationResults.push(result)
338
- }
339
- results.push(iterationResults)
340
-
341
- // 检查终止条件
342
- if (step.until) {
343
- let shouldStop = false
344
- if (typeof step.until === 'function') {
345
- shouldStop = step.until(context)
346
- } else if (typeof step.until === 'string') {
347
- const fn = new Function('context', `with(context.variables) { return (${step.until}) }`)
348
- shouldStop = fn(context)
349
- }
350
-
351
- if (shouldStop) {
352
- console.log(`[StepExecutor] Loop terminated at iteration ${i}`)
353
- break
354
- }
355
- }
356
- }
357
-
358
- return results
359
- }
360
-
361
- /**
362
- * 执行延迟步骤
363
- */
364
- async executeDelay(step, context) {
365
- const delayMs = step.delayMs || 1000
366
- console.log(`[StepExecutor] Delaying ${delayMs}ms`)
367
- await new Promise(resolve => setTimeout(resolve, delayMs))
368
- return null
369
- }
370
-
371
- /**
372
- * 执行顺序步骤
373
- */
374
- async executeSequential(step, context) {
375
- console.log(`[StepExecutor] Executing sequential: ${step.name || step.id}`)
376
- return await this.executeSteps(step.steps || [], context)
377
- }
378
-
379
- /**
380
- * 执行消息步骤(ExplorerLoop 专用)
381
- */
382
- async executeMessage(step, context) {
383
- console.log(`[StepExecutor] Executing message step`)
384
-
385
- // 使用子Agent处理消息,避免阻塞主agent
386
- const messageAgent = this.framework.createSubAgent({
387
- name: 'workflow_message',
388
- role: '工作流任务执行助手,专注于处理工作流中的消息任务'
389
- })
390
-
391
- let content = step.content || ''
392
- // 支持变量引用
393
- content = this._resolveValue(content, context)
394
-
395
- // 如果有事件上下文,附加到消息
396
- if (context.variables?._event) {
397
- content = `${content}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
398
- }
399
-
400
- const result = await messageAgent.chat(content)
401
- return { success: true, result }
402
- }
403
-
404
- /**
405
- * 执行思考步骤(ExplorerLoop 专用)
406
- */
407
- async executeThink(step, context) {
408
- console.log(`[StepExecutor] Executing think step`)
409
-
410
- const thinkPlugin = this.framework.pluginManager?.get('think')
411
- if (!thinkPlugin) {
412
- return { success: false, error: '思考插件不可用' }
413
- }
414
-
415
- let topic = step.topic || 'Ambient代理反思'
416
- topic = this._resolveValue(topic, context)
417
-
418
- if (context.variables?._event) {
419
- topic = `${topic}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`
420
- }
421
-
422
- const result = await thinkPlugin._triggerThinking({
423
- topic,
424
- mode: step.mode || 'reflect',
425
- depth: step.depth || 2
426
- })
427
-
428
- return result
429
- }
430
-
431
- /**
432
- * 获取活跃代理
433
- */
434
- _getActiveAgent() {
435
- if (this.framework._mainAgent) {
436
- return this.framework._mainAgent
437
- }
438
- const agents = this.framework._agents || []
439
- return agents.length > 0 ? agents[agents.length - 1] : null
440
- }
441
-
442
- /**
443
- * 解析参数中的变量引用
444
- */
445
- _resolveArgs(args, context) {
446
- const resolved = {}
447
- for (const [key, value] of Object.entries(args)) {
448
- resolved[key] = this._resolveValue(value, context)
449
- }
450
- return resolved
451
- }
452
-
453
- _resolveValue(value, context) {
454
- if (typeof value === 'string') {
455
- // 支持多种引用格式:
456
- // {{result}} - 上一步结果 (lastResult)
457
- // {{result.body.ip}} - 从上一步结果提取嵌套字段
458
- // {{variables.xxx}} - 显式引用 context.variables
459
- // {{context.xxx}} - 显式引用 context 根属性
460
- // {{lastResult}} - 上一步结果(result 的别名)
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) => {
490
- // result lastResult 都指向 context.lastResult
491
- if (path === 'result' || path === 'lastResult') {
492
- return context.lastResult ?? match
493
- }
494
- if (path.startsWith('result.') || path.startsWith('lastResult.')) {
495
- const nestedPath = path.replace(/^(result|lastResult)\./, '')
496
- const val = this._getNestedValue(context.lastResult, nestedPath)
497
- if (val !== undefined) return val
498
- return match
499
- }
500
- if (path.startsWith('variables.')) {
501
- return this._getNestedValue(context, path) ?? match
502
- } else if (path.startsWith('context.')) {
503
- return this._getNestedValue(context, path) ?? match
504
- } else {
505
- // 先从 variables 查找,再从 context 根属性查找
506
- const val = this._getNestedValue(context.variables, path)
507
- if (val !== undefined) return val
508
- return this._getNestedValue(context, path) ?? match
509
- }
510
- })
511
-
512
- return result
513
- } else if (Array.isArray(value)) {
514
- return value.map(v => this._resolveValue(v, context))
515
- } else if (typeof value === 'object' && value !== null) {
516
- const resolved = {}
517
- for (const [k, v] of Object.entries(value)) {
518
- resolved[k] = this._resolveValue(v, context)
519
- }
520
- return resolved
521
- }
522
- return value
523
- }
524
-
525
- _getNestedValue(obj, path) {
526
- if (!obj) return undefined
527
- const parts = path.split('.')
528
- let current = obj
529
- for (const part of parts) {
530
- if (current === null || current === undefined) return undefined
531
- // 如果当前值是字符串,尝试解析为 JSON
532
- if (typeof current === 'string' && part !== '0' && part !== 'length') {
533
- try {
534
- current = JSON.parse(current)
535
- } catch {
536
- // 解析失败,继续用原值
537
- }
538
- }
539
- current = current[part]
540
- }
541
- return current
542
- }
543
- }
544
-
545
- /**
546
- * 工作流步骤基类
547
- */
548
- class WorkflowStep {
549
- constructor(config) {
550
- this.id = config.id || `step_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
551
- this.type = config.type
552
- this.name = config.name || ''
553
- this.description = config.description || ''
554
- this.condition = config.condition || null
555
- this.timeout = config.timeout || 30000
556
- this.retry = config.retry || { enabled: false, maxAttempts: 3, delay: 1000 }
557
- this.onSuccess = config.onSuccess || null
558
- this.onFailure = config.onFailure || null
559
- }
560
-
561
- async execute(context, engine) {
562
- throw new Error('execute() must be implemented by subclass')
563
- }
564
-
565
- validate() {
566
- if (!this.type) {
567
- throw new Error('Step must have a type')
568
- }
569
- return true
570
- }
571
- }
572
-
573
- /**
574
- * 脚本步骤
575
- */
576
- class ScriptStep extends WorkflowStep {
577
- constructor(config) {
578
- super({ ...config, type: StepType.SCRIPT })
579
- this.script = config.script
580
- this.outputVariable = config.outputVariable || null
581
- }
582
-
583
- async execute(context, engine) {
584
- // 使用 StepExecutor 执行脚本逻辑
585
- const executor = new StepExecutor(engine.framework)
586
- const stepConfig = {
587
- id: this.id,
588
- name: this.name,
589
- type: StepType.SCRIPT,
590
- script: this.script,
591
- outputVariable: this.outputVariable
592
- }
593
- return await executor.executeScript(stepConfig, context)
594
- }
595
- }
596
-
597
- /**
598
- * 条件步骤
599
- */
600
- class ConditionStep extends WorkflowStep {
601
- constructor(config) {
602
- super({ ...config, type: StepType.CONDITION })
603
- this.branches = config.branches || []
604
- this.defaultBranch = config.defaultBranch || null
605
- }
606
-
607
- async execute(context, engine) {
608
- const executor = new StepExecutor(engine.framework)
609
- const stepConfig = {
610
- id: this.id,
611
- name: this.name,
612
- type: StepType.CONDITION,
613
- branches: this.branches,
614
- defaultBranch: this.defaultBranch
615
- }
616
- return await executor.executeCondition(stepConfig, context)
617
- }
618
- }
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
-
712
- /**
713
- * 顺序步骤
714
- */
715
- class SequentialStep extends WorkflowStep {
716
- constructor(config) {
717
- super({ ...config, type: StepType.SEQUENTIAL })
718
- this.steps = config.steps || []
719
- }
720
-
721
- async execute(context, engine) {
722
- const executor = new StepExecutor(engine.framework)
723
- const stepConfig = {
724
- id: this.id,
725
- name: this.name,
726
- type: StepType.SEQUENTIAL,
727
- steps: this.steps
728
- }
729
- return await executor.executeSequential(stepConfig, context)
730
- }
731
- }
732
-
733
- /**
734
- * 循环步骤
735
- */
736
- class LoopStep extends WorkflowStep {
737
- constructor(config) {
738
- super({ ...config, type: StepType.LOOP })
739
- this.maxIterations = config.maxIterations || 10
740
- this.loopVariable = config.loopVariable || 'loopIndex'
741
- this.steps = config.steps || []
742
- this.until = config.until || null
743
- }
744
-
745
- async execute(context, engine) {
746
- const executor = new StepExecutor(engine.framework)
747
- const stepConfig = {
748
- id: this.id,
749
- name: this.name,
750
- type: StepType.LOOP,
751
- maxIterations: this.maxIterations,
752
- loopVariable: this.loopVariable,
753
- steps: this.steps,
754
- until: this.until
755
- }
756
- return await executor.executeLoop(stepConfig, context)
757
- }
758
- }
759
-
760
- /**
761
- * 延迟步骤
762
- */
763
- class DelayStep extends WorkflowStep {
764
- constructor(config) {
765
- super({ ...config, type: StepType.DELAY })
766
- this.delayMs = config.delayMs || 1000
767
- }
768
-
769
- async execute(context, engine) {
770
- const executor = new StepExecutor(engine.framework)
771
- const stepConfig = {
772
- id: this.id,
773
- name: this.name,
774
- type: StepType.DELAY,
775
- delayMs: this.delayMs
776
- }
777
- return await executor.executeDelay(stepConfig, context)
778
- }
779
- }
780
-
781
- /**
782
- * 工具步骤
783
- */
784
- class ToolStep extends WorkflowStep {
785
- constructor(config) {
786
- super({ ...config, type: StepType.TOOL })
787
- this.tool = config.tool
788
- this.args = config.args || {}
789
- this.outputVariable = config.outputVariable || null
790
- this.output = config.output || null // 兼容旧格式
791
- this.input = config.input || null // 兼容旧格式:input 字段
792
- }
793
-
794
- async execute(context, engine) {
795
- const executor = new StepExecutor(engine.framework)
796
- const stepConfig = {
797
- id: this.id,
798
- name: this.name,
799
- type: StepType.TOOL,
800
- tool: this.tool,
801
- args: this.args,
802
- outputVariable: this.outputVariable,
803
- output: this.output, // 传递 output
804
- input: this.input // 传递 input
805
- }
806
- return await executor.executeTool(stepConfig, context)
807
- }
808
- }
809
-
810
- /**
811
- * 工作流引擎
812
- */
813
- class WorkflowEngine extends EventEmitter {
814
- constructor(framework) {
815
- super()
816
- this.framework = framework
817
- this._steps = new Map()
818
- }
819
-
820
- /**
821
- * 注册自定义步骤类型
822
- */
823
- registerStepType(type, StepClass) {
824
- this._steps.set(type, StepClass)
825
- }
826
-
827
- /**
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 类型
840
- */
841
- createStep(config) {
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)
878
-
879
- if (!StepClass) {
880
- throw new Error(`Unknown step type: ${type}`)
881
- }
882
-
883
- // 确保配置有 type 字段
884
- return new StepClass({ ...config, type })
885
- }
886
-
887
- /**
888
- * 创建工作流上下文
889
- */
890
- createContext(input = {}, variables = {}) {
891
- return {
892
- input,
893
- variables,
894
- lastResult: null,
895
- results: []
896
- }
897
- }
898
- }
899
-
900
- /**
901
- * WorkflowManagerPlugin
902
- */
903
- class WorkflowPlugin extends Plugin {
904
- constructor(config = {}) {
905
- super()
906
- this.name = 'workflow'
907
- this.version = '1.0.0'
908
- this.description = '工作流引擎,支持结构化工作流定义和执行'
909
- this.priority = 6
910
- this.system = true
911
-
912
- this._framework = null
913
- this._engine = null
914
- this._workflowsDir = config.workflowsDir || '.agent/workflows'
915
- this._workflows = new Map()
916
- this._workflowTools = new Map()
917
- }
918
-
919
- install(framework) {
920
- this._framework = framework
921
- this._engine = new WorkflowEngine(framework)
922
-
923
- // 注册内置步骤类型
924
- this._engine.registerStepType(StepType.SCRIPT, ScriptStep)
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)
929
- this._engine.registerStepType(StepType.SEQUENTIAL, SequentialStep)
930
- this._engine.registerStepType(StepType.LOOP, LoopStep)
931
- this._engine.registerStepType(StepType.DELAY, DelayStep)
932
- this._engine.registerStepType(StepType.TOOL, ToolStep)
933
- this._engine.registerStepType(StepType.WORKFLOW, NestedWorkflowStep)
934
-
935
- // 注册工作流执行工具
936
- framework.registerTool({
937
- name: 'execute_workflow',
938
- description: '执行指定的工作流',
939
- inputSchema: z.object({
940
- workflow: z.string().describe('工作流定义(JSON JavaScript 代码)'),
941
- input: z.object({}).optional().describe('工作流输入参数')
942
- }),
943
- execute: async (args, framework) => {
944
- // 获取当前 sessionId
945
- let sessionId = null
946
- const ctx = framework.getExecutionContext()
947
- if (ctx?.sessionId) {
948
- sessionId = ctx.sessionId
949
- }
950
- return await this.executeWorkflow(args.workflow, args.input || {}, sessionId)
951
- }
952
- })
953
-
954
- return this
955
- }
956
-
957
- start(framework) {
958
- this._loadWorkflows()
959
- this._registerWorkflowTools()
960
-
961
- // 注册 reloadWorkflows 工具
962
- framework.registerTool({
963
- name: 'reloadWorkflows',
964
- description: '重载所有工作流,当用户添加或修改工作流后调用此工具',
965
- inputSchema: z.object({}),
966
- execute: async () => {
967
- this.reload(this._framework)
968
- return {
969
- success: true,
970
- message: `Workflows reloaded. Total: ${this._workflows.size}`,
971
- workflows: Array.from(this._workflows.keys())
972
- }
973
- }
974
- })
975
-
976
- return this
977
- }
978
-
979
- /**
980
- * 加载目录中的工作流定义
981
- */
982
- _loadWorkflows() {
983
- const dir = path.resolve(process.cwd(), this._workflowsDir)
984
- if (!fs.existsSync(dir)) {
985
- fs.mkdirSync(dir, { recursive: true })
986
- console.log(`[Workflow] Created workflows directory: ${dir}`)
987
- return
988
- }
989
-
990
- try {
991
- const files = fs.readdirSync(dir)
992
- for (const file of files) {
993
- if (!file.endsWith('.json') && !file.endsWith('.js')) continue
994
-
995
- const filePath = path.join(dir, file)
996
- const workflowName = path.basename(file, path.extname(file))
997
-
998
- // 跳过已存在的工作流
999
- if (this._workflows.has(workflowName)) continue
1000
-
1001
- try {
1002
- const content = fs.readFileSync(filePath, 'utf-8')
1003
- let workflowDef
1004
-
1005
- if (file.endsWith('.js')) {
1006
- // 执行 JS 文件获取工作流定义
1007
- // eslint-disable-next-line no-new-func
1008
- const fn = new Function('module', 'exports', 'require', 'process', 'console', '__dirname', '__filename', content)
1009
- const module = { exports: {} }
1010
- fn(module, module.exports, require, process, console, path.dirname(filePath), filePath)
1011
- workflowDef = module.exports.default || module.exports
1012
- } else {
1013
- workflowDef = JSON.parse(content)
1014
- }
1015
-
1016
- if (workflowDef && workflowDef.steps) {
1017
- this._workflows.set(workflowName, workflowDef)
1018
- //console.log(`[Workflow] Loaded: ${workflowName}`)
1019
- }
1020
- } catch (err) {
1021
- console.error(`[Workflow] Failed to load ${file}:`, err.message)
1022
- }
1023
- }
1024
- } catch (err) {
1025
- console.error('[Workflow] Failed to read workflows directory:', err.message)
1026
- }
1027
- }
1028
-
1029
- /**
1030
- * 注册工作流为工具
1031
- */
1032
- _registerWorkflowTools() {
1033
- for (const [name, workflow] of this._workflows) {
1034
- if (this._workflowTools.has(name)) continue
1035
-
1036
- const toolName = `workflow_${name}`
1037
- const description = workflow.description || `执行工作流: ${name}`
1038
-
1039
- this._framework.registerTool({
1040
- name: toolName,
1041
- description,
1042
- inputSchema: z.object({
1043
- input: z.object({}).optional().describe('工作流输入参数')
1044
- }),
1045
- execute: async (args) => {
1046
- return await this.executeWorkflow(workflow, args.input || {})
1047
- }
1048
- })
1049
-
1050
- this._workflowTools.set(name, toolName)
1051
- console.log(`[Workflow] Registered tool: ${toolName}`)
1052
- }
1053
- }
1054
-
1055
- /**
1056
- * 重载工作流
1057
- */
1058
- reload(framework) {
1059
- console.log('[Workflow] Reloading...')
1060
- this._framework = framework
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
-
1077
- // 清除已注册的工具
1078
- for (const toolName of this._workflowTools.values()) {
1079
- // 工具注销需要框架支持,这里只清理内部状态
1080
- }
1081
- this._workflowTools.clear()
1082
- this._workflows.clear()
1083
-
1084
- // 重新加载
1085
- this._loadWorkflows()
1086
- this._registerWorkflowTools()
1087
-
1088
- console.log(`[Workflow] Reloaded. Total workflows: ${this._workflows.size}`)
1089
- }
1090
-
1091
- /**
1092
- * 执行工作流
1093
- */
1094
- async executeWorkflow(workflowDef, input = {}, sessionId = null) {
1095
- try {
1096
- let workflow
1097
-
1098
- if (typeof workflowDef === 'string') {
1099
- // 尝试作为工作流名称加载(先检查是否已加载的工作流)
1100
- const workflowName = workflowDef.trim()
1101
- if (this._workflows.has(workflowName)) {
1102
- workflow = this._workflows.get(workflowName)
1103
- } else {
1104
- // 尝试解析 JSON 或执行代码
1105
- try {
1106
- workflow = JSON.parse(workflowDef)
1107
- } catch {
1108
- // eslint-disable-next-line no-new-func
1109
- const fn = new Function('engine', 'return (' + workflowDef + ')')
1110
- workflow = fn(this._engine)
1111
- }
1112
- }
1113
- } else {
1114
- workflow = workflowDef
1115
- }
1116
-
1117
- const context = this._engine.createContext(input, {})
1118
-
1119
- // 将 sessionId 存储到上下文变量,供工具步骤使用
1120
- if (sessionId) {
1121
- context.variables._sessionId = sessionId
1122
- }
1123
-
1124
- // 执行工作流步骤
1125
- if (workflow.steps && Array.isArray(workflow.steps)) {
1126
- const results = []
1127
- // 按 id 存储步骤输出,供 ${id.output} 引用
1128
- context.variables._stepOutputs = {}
1129
- for (const stepConfig of workflow.steps) {
1130
- const step = this._engine.createStep(stepConfig)
1131
- const result = await step.execute(context, this._engine)
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
1157
- }
1158
- }
1159
-
1160
- return { success: true, output: {} }
1161
- } catch (err) {
1162
- return { success: false, error: err.message }
1163
- }
1164
- }
1165
-
1166
- /**
1167
- * 获取引擎
1168
- */
1169
- getEngine() {
1170
- return this._engine
1171
- }
1172
-
1173
- uninstall(framework) {
1174
- this._engine = null
1175
- this._framework = null
1176
- }
1177
- }
1178
-
1179
- module.exports = {
1180
- WorkflowPlugin,
1181
- WorkflowEngine,
1182
- WorkflowStep,
1183
- StepType,
1184
- StepExecutor,
1185
- ScriptStep,
1186
- ConditionStep,
1187
- ParallelStep,
1188
- SwitchStep,
1189
- TryStep,
1190
- NestedWorkflowStep,
1191
- SequentialStep,
1192
- LoopStep,
1193
- DelayStep,
1194
- ToolStep
1195
- }
1
+ /**
2
+ * WorkflowEngine 工作流引擎
3
+ * 支持结构化工作流定义和执行
4
+ */
5
+ const { EventEmitter } = require('../utils/event-emitter');
6
+ const { Plugin } = require('../core/plugin-base');
7
+ const { logger } = require('../utils/logger');
8
+ const log = logger.child('Workflow');
9
+ const { z } = require('zod');
10
+ const { runScriptSafely, evaluateInSandbox, runWorkflowFileSafely, runWorkflowSafely } = require('../utils/sandbox');
11
+ const fs = require('fs');
12
+ const crypto = require('crypto');
13
+ const path = require('path');
14
+ /**
15
+ * 工作流步骤类型
16
+ */
17
+ const StepType = {
18
+ AGENT: 'agent',
19
+ SCRIPT: 'script',
20
+ CONDITION: 'condition',
21
+ SWITCH: 'switch',
22
+ TRY: 'try',
23
+ PARALLEL: 'parallel',
24
+ SEQUENTIAL: 'sequential',
25
+ LOOP: 'loop',
26
+ DELAY: 'delay',
27
+ TOOL: 'tool',
28
+ INPUT: 'input',
29
+ OUTPUT: 'output',
30
+ MESSAGE: 'message',
31
+ THINK: 'think',
32
+ WORKFLOW: 'workflow', // 嵌套工作流
33
+ };
34
+ /**
35
+ * StepExecutor - 统一的步骤执行器
36
+ * 同时被 WorkflowEngine 和 ExplorerLoop 使用
37
+ */
38
+ class StepExecutor {
39
+ constructor(framework) {
40
+ this.framework = framework;
41
+ this._log = logger.child('StepExecutor');
42
+ }
43
+ /**
44
+ * 执行单个步骤
45
+ */
46
+ async executeStep(step, context) {
47
+ const handler = this._getStepHandler(step.type);
48
+ if (!handler) {
49
+ throw new Error(`Unknown step type: ${step.type}`);
50
+ }
51
+ return await handler.call(this, step, context);
52
+ }
53
+ /**
54
+ * 执行多个步骤(顺序)
55
+ */
56
+ async executeSteps(steps, context) {
57
+ const results = [];
58
+ for (const step of steps) {
59
+ const result = await this.executeStep(step, context);
60
+ results.push(result);
61
+ }
62
+ return results;
63
+ }
64
+ /**
65
+ * 获取步骤类型处理器
66
+ */
67
+ _getStepHandler(type) {
68
+ const handlers = {
69
+ [StepType.TOOL]: this.executeTool,
70
+ [StepType.SCRIPT]: this.executeScript,
71
+ [StepType.CONDITION]: this.executeCondition,
72
+ [StepType.SWITCH]: this.executeSwitch,
73
+ [StepType.TRY]: this.executeTry,
74
+ [StepType.PARALLEL]: this.executeParallel,
75
+ [StepType.LOOP]: this.executeLoop,
76
+ [StepType.DELAY]: this.executeDelay,
77
+ [StepType.SEQUENTIAL]: this.executeSequential,
78
+ [StepType.MESSAGE]: this.executeMessage,
79
+ [StepType.THINK]: this.executeThink,
80
+ [StepType.WORKFLOW]: this.executeWorkflowStep,
81
+ };
82
+ return handlers[type];
83
+ }
84
+ /**
85
+ * 执行 switch 步骤
86
+ */
87
+ async executeSwitch(step, context) {
88
+ this._log.debug(` Executing switch: ${step.name || step.id}`);
89
+ const value = this._resolveValue(step.value, context);
90
+ const branches = step.branches || [];
91
+ for (const branch of branches) {
92
+ const caseValue = this._resolveValue(branch.case, context);
93
+ if (value === caseValue) {
94
+ this._log.debug(` Switch matched case: ${caseValue}`);
95
+ if (branch.steps && branch.steps.length > 0) {
96
+ return await this.executeSteps(branch.steps, context);
97
+ }
98
+ return { matched: caseValue };
99
+ }
100
+ }
101
+ // 默认分支
102
+ if (step.default && step.default.steps) {
103
+ this._log.debug(` Executing switch default branch`);
104
+ return await this.executeSteps(step.default.steps, context);
105
+ }
106
+ return { matched: null, value };
107
+ }
108
+ /**
109
+ * 执行 try-catch 步骤
110
+ */
111
+ async executeTry(step, context) {
112
+ this._log.debug(` Executing try-catch: ${step.name || step.id}`);
113
+ try {
114
+ if (step.try && step.try.steps) {
115
+ const result = await this.executeSteps(step.try.steps, context);
116
+ return { success: true, result };
117
+ }
118
+ return { success: true };
119
+ } catch (err) {
120
+ this._log.debug(` Try block failed, executing catch: ${err.message}`);
121
+ if (step.catch && step.catch.steps) {
122
+ const catchResult = await this.executeSteps(step.catch.steps, context);
123
+ return { success: false, error: err.message, caught: catchResult };
124
+ }
125
+ return { success: false, error: err.message };
126
+ }
127
+ }
128
+ /**
129
+ * 执行嵌套工作流步骤
130
+ */
131
+ async executeWorkflowStep(step, context) {
132
+ this._log.debug(` Executing nested workflow: ${step.name || step.id}`);
133
+ if (!step.workflow) {
134
+ throw new Error('Workflow step requires a workflow definition');
135
+ }
136
+ // 执行嵌套工作流
137
+ const result = await this.framework.pluginManager
138
+ .get('workflow')
139
+ .executeWorkflow(step.workflow, step.input || {}, context.variables._sessionId);
140
+ // 将嵌套工作流的输出合并到当前上下文
141
+ if (result.output) {
142
+ for (const [key, value] of Object.entries(result.output)) {
143
+ context.variables[key] = value;
144
+ }
145
+ }
146
+ return result;
147
+ }
148
+ /**
149
+ * 执行并行步骤
150
+ */
151
+ async executeParallel(step, context) {
152
+ this._log.debug(` Executing parallel: ${step.name || step.id}`);
153
+ const steps = step.steps || [];
154
+ if (steps.length === 0) {
155
+ return [];
156
+ }
157
+ // 并行执行所有步骤
158
+ const promises = steps.map((stepConfig) => {
159
+ return this.executeStep(stepConfig, context);
160
+ });
161
+ const results = await Promise.all(promises);
162
+ return results;
163
+ }
164
+ /**
165
+ * 执行工具步骤
166
+ */
167
+ async executeTool(step, context) {
168
+ if (!step.tool) {
169
+ throw new Error('Tool step requires a tool name');
170
+ }
171
+ this._log.debug(` Executing tool: ${step.tool}`);
172
+ // 解析工具参数,支持变量引用
173
+ let resolvedArgs = this._resolveArgs(step.args || {}, context);
174
+ // 兼容旧格式:处理 step.input 字段(${stepId.output} 引用)
175
+ // 将 input 注入到 args.input_data,供 python-execute 使用
176
+ if (step.input) {
177
+ const resolvedInput = this._resolveArgs(step.input, context);
178
+ resolvedArgs.input_data = resolvedInput;
179
+ }
180
+ // 获取当前 sessionId
181
+ let sessionId = context.variables?._sessionId;
182
+ if (!sessionId && this.framework.getExecutionContext) {
183
+ const ctx = this.framework.getExecutionContext();
184
+ sessionId = ctx?.sessionId;
185
+ }
186
+ // 执行工具
187
+ let result;
188
+ if (sessionId && this.framework.runWithContext) {
189
+ result = await this.framework.runWithContext(
190
+ { sessionId },
191
+ async () => await this.framework.executeTool(step.tool, resolvedArgs)
192
+ );
193
+ } else {
194
+ result = await this.framework.executeTool(step.tool, resolvedArgs);
195
+ }
196
+ // 保存结果到变量
197
+ // 支持 output 作为 outputVariable 的别名
198
+ const outputVar = step.outputVariable || step.output;
199
+ if (outputVar) {
200
+ context.variables[outputVar] = result;
201
+ }
202
+ context.lastResult = result;
203
+ if (result && result.error) {
204
+ this._log.warn(` Tool ${step.tool} returned error: ${result.error}`);
205
+ }
206
+ return result;
207
+ }
208
+ /**
209
+ * 执行脚本步骤
210
+ */
211
+ async executeScript(step, context) {
212
+ this._log.debug(` Executing script step: ${step.name || step.id}`);
213
+ // 安全警告:使用 new Function() 执行用户脚本存在风险
214
+ if (typeof step.script === 'string') {
215
+ this._log.warn(
216
+ ` [SECURITY WARNING] Executing user script via new Function() - ensure script is from trusted source`
217
+ );
218
+ }
219
+ try {
220
+ // 兼容旧格式:处理 step.input 字段(${stepId.output} 引用)
221
+ let resolvedInput = context.input || {};
222
+ if (step.input && typeof step.input === 'object') {
223
+ resolvedInput = this._resolveArgs(step.input, context);
224
+ }
225
+ const scriptContext = {
226
+ input: resolvedInput,
227
+ input_data: resolvedInput, // 兼容 input_data 变量名
228
+ variables: context.variables,
229
+ previousResult: context.lastResult,
230
+ console: {
231
+ log: (...args) => {
232
+ const s = logger.child('Script');
233
+ s.debug(`[\${step.id}]`, ...args);
234
+ },
235
+ },
236
+ };
237
+ let result;
238
+ if (typeof step.script === 'function') {
239
+ result = await step.script(scriptContext);
240
+ } else if (typeof step.script === 'string') {
241
+ // 使用沙箱执行用户脚本,防止恶意代码执行
242
+ result = await runScriptSafely(step.script, scriptContext, { timeout: 10000 });
243
+ }
244
+ // 支持 output 作为 outputVariable 的别名
245
+ const outputVar = step.outputVariable || step.output;
246
+ if (outputVar) {
247
+ context.variables[outputVar] = result;
248
+ }
249
+ context.lastResult = result;
250
+ return result;
251
+ } catch (err) {
252
+ throw new Error(`Script execution failed: ${err.message}`);
253
+ }
254
+ }
255
+ /**
256
+ * 执行条件步骤
257
+ */
258
+ async executeCondition(step, context) {
259
+ this._log.debug(` Evaluating condition: ${step.name || step.id}`);
260
+ for (const branch of step.branches || []) {
261
+ try {
262
+ let conditionValue;
263
+ if (typeof branch.condition === 'function') {
264
+ conditionValue = branch.condition(context);
265
+ } else if (typeof branch.condition === 'string') {
266
+ // 使用沙箱评估条件,防止恶意代码执行
267
+ conditionValue = await evaluateInSandbox(branch.condition, context, { timeout: 5000 });
268
+ }
269
+ if (conditionValue) {
270
+ this._log.debug(` Condition matched: ${branch.name || branch.stepId}`);
271
+ if (branch.steps && branch.steps.length > 0) {
272
+ await this.executeSteps(branch.steps, context);
273
+ }
274
+ return branch.stepId || branch.name;
275
+ }
276
+ } catch (err) {
277
+ this._log.warn(` Branch condition error:`, err.message);
278
+ }
279
+ }
280
+ // 执行默认分支
281
+ if (step.defaultBranch && step.defaultBranch.steps) {
282
+ this._log.debug(` Executing default branch`);
283
+ await this.executeSteps(step.defaultBranch.steps, context);
284
+ }
285
+ return null;
286
+ }
287
+ /**
288
+ * 执行循环步骤
289
+ */
290
+ async executeLoop(step, context) {
291
+ this._log.debug(` Executing loop: ${step.name || step.id}`);
292
+ const results = [];
293
+ const maxIterations = step.maxIterations || 10;
294
+ const loopVariable = step.loopVariable || 'loopIndex';
295
+ for (let i = 0; i < maxIterations; i++) {
296
+ context.variables[loopVariable] = i;
297
+ this._log.debug(` Loop iteration ${i}`);
298
+ const iterationResults = [];
299
+ for (const stepConfig of step.steps || []) {
300
+ const result = await this.executeStep(stepConfig, context);
301
+ iterationResults.push(result);
302
+ }
303
+ results.push(iterationResults);
304
+ // 检查终止条件
305
+ if (step.until) {
306
+ let shouldStop = false;
307
+ if (typeof step.until === 'function') {
308
+ shouldStop = step.until(context);
309
+ } else if (typeof step.until === 'string') {
310
+ // 使用沙箱评估循环条件,防止恶意代码执行
311
+ shouldStop = await evaluateInSandbox(step.until, context, { timeout: 5000 });
312
+ }
313
+ if (shouldStop) {
314
+ this._log.debug(` Loop terminated at iteration ${i}`);
315
+ break;
316
+ }
317
+ }
318
+ }
319
+ return results;
320
+ }
321
+ /**
322
+ * 执行延迟步骤
323
+ */
324
+ async executeDelay(step, context) {
325
+ const delayMs = step.delayMs || 1000;
326
+ this._log.debug(` Delaying ${delayMs}ms`);
327
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
328
+ return null;
329
+ }
330
+ /**
331
+ * 执行顺序步骤
332
+ */
333
+ async executeSequential(step, context) {
334
+ this._log.debug(` Executing sequential: ${step.name || step.id}`);
335
+ return await this.executeSteps(step.steps || [], context);
336
+ }
337
+ /**
338
+ * 执行消息步骤(ExplorerLoop 专用)
339
+ */
340
+ async executeMessage(step, context) {
341
+ this._log.debug(` Executing message step`);
342
+ // 使用子Agent处理消息,避免阻塞主agent
343
+ const messageAgent = this.framework.createSubAgent({
344
+ name: 'workflow_message',
345
+ role: '工作流任务执行助手,专注于处理工作流中的消息任务',
346
+ });
347
+ let content = step.content || '';
348
+ // 支持变量引用
349
+ content = this._resolveValue(content, context);
350
+ // 如果有事件上下文,附加到消息
351
+ if (context.variables?._event) {
352
+ content = `${content}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`;
353
+ }
354
+ const result = await messageAgent.chat(content);
355
+ return { success: true, result };
356
+ }
357
+ /**
358
+ * 执行思考步骤(ExplorerLoop 专用)
359
+ */
360
+ async executeThink(step, context) {
361
+ this._log.debug(` Executing think step`);
362
+ const thinkPlugin = this.framework.pluginManager?.get('think');
363
+ if (!thinkPlugin) {
364
+ return { success: false, error: '思考插件不可用' };
365
+ }
366
+ let topic = step.topic || 'Ambient代理反思';
367
+ topic = this._resolveValue(topic, context);
368
+ if (context.variables?._event) {
369
+ topic = `${topic}\n\n[事件上下文: ${JSON.stringify(context.variables._event)}]`;
370
+ }
371
+ const result = await thinkPlugin._triggerThinking({
372
+ topic,
373
+ mode: step.mode || 'reflect',
374
+ depth: step.depth || 2,
375
+ });
376
+ return result;
377
+ }
378
+ /**
379
+ * 获取活跃代理
380
+ */
381
+ _getActiveAgent() {
382
+ if (this.framework._mainAgent) {
383
+ return this.framework._mainAgent;
384
+ }
385
+ const agents = this.framework._agents || [];
386
+ return agents.length > 0 ? agents[agents.length - 1] : null;
387
+ }
388
+ /**
389
+ * 解析参数中的变量引用
390
+ */
391
+ _resolveArgs(args, context) {
392
+ const resolved = {};
393
+ for (const [key, value] of Object.entries(args)) {
394
+ resolved[key] = this._resolveValue(value, context);
395
+ }
396
+ return resolved;
397
+ }
398
+ _resolveValue(value, context) {
399
+ if (typeof value === 'string') {
400
+ // 支持多种引用格式:
401
+ // {{result}} - 上一步结果 (lastResult)
402
+ // {{result.body.ip}} - 从上一步结果提取嵌套字段
403
+ // {{variables.xxx}} - 显式引用 context.variables
404
+ // {{context.xxx}} - 显式引用 context 根属性
405
+ // {{lastResult}} - 上一步结果(result 的别名)
406
+ // ${stepId.output} - 引用指定 id 步骤的输出(兼容旧格式)
407
+ // ${stepId.output.path} - 从指定步骤输出提取字段
408
+ let result = value;
409
+ // 先处理 ${stepId.output} 格式(兼容旧格式)
410
+ result = result.replace(/\$\{([^}]+)\}/g, (match, path) => {
411
+ const stepOutputs = context.variables._stepOutputs || {};
412
+ if (path === 'output') {
413
+ // ${output} 等同于 ${stepId.output} 引用上一步
414
+ return context.lastResult ?? match;
415
+ }
416
+ if (path.includes('.')) {
417
+ // ${stepId.output.field} 格式
418
+ const [stepId, ...fieldParts] = path.split('.');
419
+ const stepOutput = stepOutputs[stepId];
420
+ if (stepOutput !== undefined) {
421
+ const val = this._getNestedValue(stepOutput, fieldParts.join('.'));
422
+ if (val !== undefined) return val;
423
+ }
424
+ } else {
425
+ // ${stepId.output} 格式
426
+ const stepOutput = stepOutputs[path];
427
+ if (stepOutput !== undefined) return stepOutput;
428
+ }
429
+ return match;
430
+ });
431
+ // 再处理 {{...}} 格式(支持 _event.email.from 等嵌套属性)
432
+ result = result.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
433
+ // result 和 lastResult 都指向 context.lastResult
434
+ if (path === 'result' || path === 'lastResult') {
435
+ return context.lastResult ?? match;
436
+ }
437
+ if (path.startsWith('result.') || path.startsWith('lastResult.')) {
438
+ const nestedPath = path.replace(/^(result|lastResult)\./, '');
439
+ const val = this._getNestedValue(context.lastResult, nestedPath);
440
+ if (val !== undefined) return val;
441
+ return match;
442
+ }
443
+ if (path.startsWith('variables.')) {
444
+ return this._getNestedValue(context, path) ?? match;
445
+ } else if (path.startsWith('context.')) {
446
+ return this._getNestedValue(context, path) ?? match;
447
+ } else {
448
+ // 先从 variables 查找,再从 context 根属性查找
449
+ const val = this._getNestedValue(context.variables, path);
450
+ if (val !== undefined) return val;
451
+ return this._getNestedValue(context, path) ?? match;
452
+ }
453
+ });
454
+ return result;
455
+ } else if (Array.isArray(value)) {
456
+ return value.map((v) => this._resolveValue(v, context));
457
+ } else if (typeof value === 'object' && value !== null) {
458
+ const resolved = {};
459
+ for (const [k, v] of Object.entries(value)) {
460
+ resolved[k] = this._resolveValue(v, context);
461
+ }
462
+ return resolved;
463
+ }
464
+ return value;
465
+ }
466
+ _getNestedValue(obj, path) {
467
+ if (!obj) return undefined;
468
+ const parts = path.split('.');
469
+ let current = obj;
470
+ for (const part of parts) {
471
+ if (current === null || current === undefined) return undefined;
472
+ // 如果当前值是字符串,尝试解析为 JSON
473
+ if (typeof current === 'string' && part !== '0' && part !== 'length') {
474
+ try {
475
+ current = JSON.parse(current);
476
+ } catch {
477
+ // 解析失败,继续用原值
478
+ }
479
+ }
480
+ current = current[part];
481
+ }
482
+ return current;
483
+ }
484
+ }
485
+ /**
486
+ * 工作流步骤基类
487
+ */
488
+ class WorkflowStep {
489
+ constructor(config) {
490
+ this.id = config.id || `step_${Date.now()}_${crypto.randomBytes(6).toString('base64url')}`;
491
+ this.type = config.type;
492
+ this.name = config.name || '';
493
+ this.description = config.description || '';
494
+ this.condition = config.condition || null;
495
+ this.timeout = config.timeout || 30000;
496
+ this.retry = config.retry || { enabled: false, maxAttempts: 3, delay: 1000 };
497
+ this.onSuccess = config.onSuccess || null;
498
+ this.onFailure = config.onFailure || null;
499
+ }
500
+ async execute(context, engine) {
501
+ throw new Error('execute() must be implemented by subclass');
502
+ }
503
+ validate() {
504
+ if (!this.type) {
505
+ throw new Error('Step must have a type');
506
+ }
507
+ return true;
508
+ }
509
+ }
510
+ /**
511
+ * 脚本步骤
512
+ */
513
+ class ScriptStep extends WorkflowStep {
514
+ constructor(config) {
515
+ super({ ...config, type: StepType.SCRIPT });
516
+ this.script = config.script;
517
+ this.outputVariable = config.outputVariable || null;
518
+ }
519
+ async execute(context, engine) {
520
+ // 使用 StepExecutor 执行脚本逻辑
521
+ const executor = new StepExecutor(engine.framework);
522
+ const stepConfig = {
523
+ id: this.id,
524
+ name: this.name,
525
+ type: StepType.SCRIPT,
526
+ script: this.script,
527
+ outputVariable: this.outputVariable,
528
+ };
529
+ return await executor.executeScript(stepConfig, context);
530
+ }
531
+ }
532
+ /**
533
+ * 条件步骤
534
+ */
535
+ class ConditionStep extends WorkflowStep {
536
+ constructor(config) {
537
+ super({ ...config, type: StepType.CONDITION });
538
+ this.branches = config.branches || [];
539
+ this.defaultBranch = config.defaultBranch || null;
540
+ }
541
+ async execute(context, engine) {
542
+ const executor = new StepExecutor(engine.framework);
543
+ const stepConfig = {
544
+ id: this.id,
545
+ name: this.name,
546
+ type: StepType.CONDITION,
547
+ branches: this.branches,
548
+ defaultBranch: this.defaultBranch,
549
+ };
550
+ return await executor.executeCondition(stepConfig, context);
551
+ }
552
+ }
553
+ /**
554
+ * 并行步骤
555
+ */
556
+ class ParallelStep extends WorkflowStep {
557
+ constructor(config) {
558
+ super({ ...config, type: StepType.PARALLEL });
559
+ this.steps = config.steps || [];
560
+ }
561
+ async execute(context, engine) {
562
+ const executor = new StepExecutor(engine.framework);
563
+ const stepConfig = {
564
+ id: this.id,
565
+ name: this.name,
566
+ type: StepType.PARALLEL,
567
+ steps: this.steps,
568
+ };
569
+ return await executor.executeParallel(stepConfig, context);
570
+ }
571
+ }
572
+ /**
573
+ * Switch 步骤
574
+ */
575
+ class SwitchStep extends WorkflowStep {
576
+ constructor(config) {
577
+ super({ ...config, type: StepType.SWITCH });
578
+ this.value = config.value;
579
+ this.branches = config.branches || [];
580
+ this.default = config.default || null;
581
+ }
582
+ async execute(context, engine) {
583
+ const executor = new StepExecutor(engine.framework);
584
+ const stepConfig = {
585
+ id: this.id,
586
+ name: this.name,
587
+ type: StepType.SWITCH,
588
+ value: this.value,
589
+ branches: this.branches,
590
+ default: this.default,
591
+ };
592
+ return await executor.executeSwitch(stepConfig, context);
593
+ }
594
+ }
595
+ /**
596
+ * Try-Catch 步骤
597
+ */
598
+ class TryStep extends WorkflowStep {
599
+ constructor(config) {
600
+ super({ ...config, type: StepType.TRY });
601
+ this.try = config.try || {};
602
+ this.catch = config.catch || {};
603
+ }
604
+ async execute(context, engine) {
605
+ const executor = new StepExecutor(engine.framework);
606
+ const stepConfig = {
607
+ id: this.id,
608
+ name: this.name,
609
+ type: StepType.TRY,
610
+ try: this.try,
611
+ catch: this.catch,
612
+ };
613
+ return await executor.executeTry(stepConfig, context);
614
+ }
615
+ }
616
+ /**
617
+ * 嵌套工作流步骤
618
+ */
619
+ class NestedWorkflowStep extends WorkflowStep {
620
+ constructor(config) {
621
+ super({ ...config, type: StepType.WORKFLOW });
622
+ this.workflow = config.workflow;
623
+ this.input = config.input || {};
624
+ }
625
+ async execute(context, engine) {
626
+ const executor = new StepExecutor(engine.framework);
627
+ const stepConfig = {
628
+ id: this.id,
629
+ name: this.name,
630
+ type: StepType.WORKFLOW,
631
+ workflow: this.workflow,
632
+ input: this.input,
633
+ };
634
+ return await executor.executeWorkflowStep(stepConfig, context);
635
+ }
636
+ }
637
+ /**
638
+ * 顺序步骤
639
+ */
640
+ class SequentialStep extends WorkflowStep {
641
+ constructor(config) {
642
+ super({ ...config, type: StepType.SEQUENTIAL });
643
+ this.steps = config.steps || [];
644
+ }
645
+ async execute(context, engine) {
646
+ const executor = new StepExecutor(engine.framework);
647
+ const stepConfig = {
648
+ id: this.id,
649
+ name: this.name,
650
+ type: StepType.SEQUENTIAL,
651
+ steps: this.steps,
652
+ };
653
+ return await executor.executeSequential(stepConfig, context);
654
+ }
655
+ }
656
+ /**
657
+ * 循环步骤
658
+ */
659
+ class LoopStep extends WorkflowStep {
660
+ constructor(config) {
661
+ super({ ...config, type: StepType.LOOP });
662
+ this.maxIterations = config.maxIterations || 10;
663
+ this.loopVariable = config.loopVariable || 'loopIndex';
664
+ this.steps = config.steps || [];
665
+ this.until = config.until || null;
666
+ }
667
+ async execute(context, engine) {
668
+ const executor = new StepExecutor(engine.framework);
669
+ const stepConfig = {
670
+ id: this.id,
671
+ name: this.name,
672
+ type: StepType.LOOP,
673
+ maxIterations: this.maxIterations,
674
+ loopVariable: this.loopVariable,
675
+ steps: this.steps,
676
+ until: this.until,
677
+ };
678
+ return await executor.executeLoop(stepConfig, context);
679
+ }
680
+ }
681
+ /**
682
+ * 延迟步骤
683
+ */
684
+ class DelayStep extends WorkflowStep {
685
+ constructor(config) {
686
+ super({ ...config, type: StepType.DELAY });
687
+ this.delayMs = config.delayMs || 1000;
688
+ }
689
+ async execute(context, engine) {
690
+ const executor = new StepExecutor(engine.framework);
691
+ const stepConfig = {
692
+ id: this.id,
693
+ name: this.name,
694
+ type: StepType.DELAY,
695
+ delayMs: this.delayMs,
696
+ };
697
+ return await executor.executeDelay(stepConfig, context);
698
+ }
699
+ }
700
+ /**
701
+ * 工具步骤
702
+ */
703
+ class ToolStep extends WorkflowStep {
704
+ constructor(config) {
705
+ super({ ...config, type: StepType.TOOL });
706
+ this.tool = config.tool;
707
+ this.args = config.args || {};
708
+ this.outputVariable = config.outputVariable || null;
709
+ this.output = config.output || null; // 兼容旧格式
710
+ this.input = config.input || null; // 兼容旧格式:input 字段
711
+ }
712
+ async execute(context, engine) {
713
+ const executor = new StepExecutor(engine.framework);
714
+ const stepConfig = {
715
+ id: this.id,
716
+ name: this.name,
717
+ type: StepType.TOOL,
718
+ tool: this.tool,
719
+ args: this.args,
720
+ outputVariable: this.outputVariable,
721
+ output: this.output, // 传递 output
722
+ input: this.input, // 传递 input
723
+ };
724
+ return await executor.executeTool(stepConfig, context);
725
+ }
726
+ }
727
+ /**
728
+ * 工作流引擎
729
+ */
730
+ class WorkflowEngine extends EventEmitter {
731
+ constructor(framework) {
732
+ super();
733
+ this.framework = framework;
734
+ this._steps = new Map();
735
+ }
736
+ /**
737
+ * 注册自定义步骤类型
738
+ */
739
+ registerStepType(type, StepClass) {
740
+ this._steps.set(type, StepClass);
741
+ }
742
+ /**
743
+ * 创建步骤实例
744
+ * 自动推断步骤类型:
745
+ * - tool 字段 -> tool 类型
746
+ * - code/script 字段 -> script 类型
747
+ * - branches 字段 -> condition 类型
748
+ * - 有 value + branches -> switch 类型
749
+ * - 有 try/catch 字段 -> try 类型
750
+ * - 有 parallel 属性 -> parallel 类型
751
+ * - 有 steps 字段 + loopVariable/maxIterations -> loop 类型
752
+ * - 有 steps 字段 -> sequential 类型
753
+ * - 有 delayMs 字段 -> delay 类型
754
+ * - 有 workflow 字段 -> workflow 类型
755
+ */
756
+ createStep(config) {
757
+ let type = config.type;
758
+ // 自动推断类型
759
+ if (!type) {
760
+ if (config.tool) {
761
+ type = StepType.TOOL;
762
+ } else if (config.code || config.script) {
763
+ type = StepType.SCRIPT;
764
+ } else if (config.try || config.catch) {
765
+ type = StepType.TRY;
766
+ } else if (config.value !== undefined && config.branches) {
767
+ type = StepType.SWITCH;
768
+ } else if (config.parallel === true || config.mode === 'parallel') {
769
+ type = StepType.PARALLEL;
770
+ } else if (config.workflow) {
771
+ type = StepType.WORKFLOW;
772
+ } else if (config.branches) {
773
+ type = StepType.CONDITION;
774
+ } else if (config.steps && (config.loopVariable || config.maxIterations)) {
775
+ type = StepType.LOOP;
776
+ } else if (config.steps) {
777
+ type = StepType.SEQUENTIAL;
778
+ } else if (config.delayMs !== undefined) {
779
+ type = StepType.DELAY;
780
+ } else if (config.message) {
781
+ type = StepType.MESSAGE;
782
+ } else if (config.topic) {
783
+ type = StepType.THINK;
784
+ }
785
+ }
786
+ if (!type) {
787
+ throw new Error(
788
+ `Cannot infer step type for step: ${JSON.stringify(config).substring(0, 100)}`
789
+ );
790
+ }
791
+ const StepClass = this._steps.get(type);
792
+ if (!StepClass) {
793
+ throw new Error(`Unknown step type: ${type}`);
794
+ }
795
+ // 确保配置有 type 字段
796
+ return new StepClass({ ...config, type });
797
+ }
798
+ /**
799
+ * 创建工作流上下文
800
+ */
801
+ createContext(input = {}, variables = {}) {
802
+ return {
803
+ input,
804
+ variables,
805
+ lastResult: null,
806
+ results: [],
807
+ };
808
+ }
809
+ }
810
+ /**
811
+ * WorkflowManagerPlugin
812
+ */
813
+ class WorkflowPlugin extends Plugin {
814
+ constructor(config = {}) {
815
+ super();
816
+ this.name = 'workflow';
817
+ this.version = '1.0.0';
818
+ this.description = '工作流引擎,支持结构化工作流定义和执行';
819
+ this.priority = 6;
820
+ this.system = true;
821
+ this._framework = null;
822
+ this._engine = null;
823
+ this._workflowsDir = config.workflowsDir || '.agent/workflows';
824
+ this._workflows = new Map();
825
+ this._workflowTools = new Map();
826
+ }
827
+ install(framework) {
828
+ this._framework = framework;
829
+ this._engine = new WorkflowEngine(framework);
830
+ // 注册内置步骤类型
831
+ this._engine.registerStepType(StepType.SCRIPT, ScriptStep);
832
+ this._engine.registerStepType(StepType.CONDITION, ConditionStep);
833
+ this._engine.registerStepType(StepType.SWITCH, SwitchStep);
834
+ this._engine.registerStepType(StepType.TRY, TryStep);
835
+ this._engine.registerStepType(StepType.PARALLEL, ParallelStep);
836
+ this._engine.registerStepType(StepType.SEQUENTIAL, SequentialStep);
837
+ this._engine.registerStepType(StepType.LOOP, LoopStep);
838
+ this._engine.registerStepType(StepType.DELAY, DelayStep);
839
+ this._engine.registerStepType(StepType.TOOL, ToolStep);
840
+ this._engine.registerStepType(StepType.WORKFLOW, NestedWorkflowStep);
841
+ // 注册工作流执行工具
842
+ framework.registerTool({
843
+ name: 'execute_workflow',
844
+ description: '执行指定的工作流',
845
+ inputSchema: z.object({
846
+ workflow: z.string().describe('工作流定义(JSON 或 JavaScript 代码)'),
847
+ input: z.object({}).optional().describe('工作流输入参数'),
848
+ }),
849
+ execute: async (args, framework) => {
850
+ // 获取当前 sessionId
851
+ let sessionId = null;
852
+ const ctx = framework.getExecutionContext();
853
+ if (ctx?.sessionId) {
854
+ sessionId = ctx.sessionId;
855
+ }
856
+ return await this.executeWorkflow(args.workflow, args.input || {}, sessionId);
857
+ },
858
+ });
859
+ return this;
860
+ }
861
+ start(framework) {
862
+ this._loadWorkflows();
863
+ this._registerWorkflowTools();
864
+ // 注册 reloadWorkflows 工具
865
+ framework.registerTool({
866
+ name: 'reloadWorkflows',
867
+ description: '重载所有工作流,当用户添加或修改工作流后调用此工具',
868
+ inputSchema: z.object({}),
869
+ execute: async () => {
870
+ this.reload(this._framework);
871
+ return {
872
+ success: true,
873
+ message: `Workflows reloaded. Total: ${this._workflows.size}`,
874
+ workflows: Array.from(this._workflows.keys()),
875
+ };
876
+ },
877
+ });
878
+ return this;
879
+ }
880
+ /**
881
+ * 加载目录中的工作流定义
882
+ */
883
+ _loadWorkflows() {
884
+ const dir = path.resolve(process.cwd(), this._workflowsDir);
885
+ if (!fs.existsSync(dir)) {
886
+ fs.mkdirSync(dir, { recursive: true });
887
+ log.info(` Created workflows directory: ${dir}`);
888
+ return;
889
+ }
890
+ try {
891
+ const files = fs.readdirSync(dir);
892
+ for (const file of files) {
893
+ if (!file.endsWith('.json') && !file.endsWith('.js')) continue;
894
+ const filePath = path.join(dir, file);
895
+ const workflowName = path.basename(file, path.extname(file));
896
+ // 跳过已存在的工作流
897
+ if (this._workflows.has(workflowName)) continue;
898
+ try {
899
+ const content = fs.readFileSync(filePath, 'utf-8');
900
+ let workflowDef;
901
+ if (file.endsWith('.js')) {
902
+ // 执行 JS 文件获取工作流定义
903
+ // 使用沙箱加载工作流文件,防止恶意代码执行
904
+ workflowDef = runWorkflowFileSafely(content, { timeout: 10000 });
905
+ if (typeof workflowDef === 'function') {
906
+ workflowDef = workflowDef(this._engine || {});
907
+ }
908
+ workflowDef = workflowDef.default || workflowDef;
909
+ } else {
910
+ workflowDef = JSON.parse(content);
911
+ }
912
+ if (workflowDef && workflowDef.steps) {
913
+ this._workflows.set(workflowName, workflowDef);
914
+ //log.info(` Loaded: ${workflowName}`)
915
+ }
916
+ } catch (err) {
917
+ log.error(` Failed to load ${file}:`, err.message);
918
+ }
919
+ }
920
+ } catch (err) {
921
+ log.error(' Failed to read workflows directory:', err.message);
922
+ }
923
+ }
924
+ /**
925
+ * 注册工作流为工具
926
+ */
927
+ _registerWorkflowTools() {
928
+ for (const [name, workflow] of this._workflows) {
929
+ if (this._workflowTools.has(name)) continue;
930
+ const toolName = `workflow_${name}`;
931
+ const description = workflow.description || `执行工作流: ${name}`;
932
+ this._framework.registerTool({
933
+ name: toolName,
934
+ description,
935
+ inputSchema: z.object({
936
+ input: z.object({}).optional().describe('工作流输入参数'),
937
+ }),
938
+ execute: async (args, framework) => {
939
+ // Get current sessionId to ensure notifications reach the correct session
940
+ let sessionId = null;
941
+ const ctx = framework?.getExecutionContext?.();
942
+ if (ctx?.sessionId) {
943
+ sessionId = ctx.sessionId;
944
+ }
945
+ return await this.executeWorkflow(workflow, args.input || {}, sessionId);
946
+ },
947
+ });
948
+ this._workflowTools.set(name, toolName);
949
+ log.info(` Registered tool: ${toolName}`);
950
+ }
951
+ }
952
+ /**
953
+ * 重载工作流
954
+ */
955
+ reload(framework) {
956
+ // 清除模块缓存,确保重新加载最新代码
957
+ const modulePath = require.resolve('./src/capabilities/workflow-engine');
958
+ if (require.cache[modulePath]) {
959
+ delete require.cache[modulePath];
960
+ }
961
+ log.info(' Reloading...');
962
+ this._framework = framework;
963
+ // 重新创建 engine(确保使用最新代码)
964
+ this._engine = new (require('./src/capabilities/workflow-engine').WorkflowEngine)(framework);
965
+ // 注册内置步骤类型
966
+ this._engine.registerStepType(
967
+ require('./src/capabilities/workflow-engine').StepType.SCRIPT,
968
+ require('./src/capabilities/workflow-engine').ScriptStep
969
+ );
970
+ this._engine.registerStepType(
971
+ require('./src/capabilities/workflow-engine').StepType.TOOL,
972
+ require('./src/capabilities/workflow-engine').ToolStep
973
+ );
974
+ this._engine.registerStepType(
975
+ require('./src/capabilities/workflow-engine').StepType.CONDITION,
976
+ require('./src/capabilities/workflow-engine').ConditionStep
977
+ );
978
+ this._engine.registerStepType(
979
+ require('./src/capabilities/workflow-engine').StepType.SWITCH,
980
+ require('./src/capabilities/workflow-engine').SwitchStep
981
+ );
982
+ this._engine.registerStepType(
983
+ require('./src/capabilities/workflow-engine').StepType.TRY,
984
+ require('./src/capabilities/workflow-engine').TryStep
985
+ );
986
+ this._engine.registerStepType(
987
+ require('./src/capabilities/workflow-engine').StepType.PARALLEL,
988
+ require('./src/capabilities/workflow-engine').ParallelStep
989
+ );
990
+ this._engine.registerStepType(
991
+ require('./src/capabilities/workflow-engine').StepType.SEQUENTIAL,
992
+ require('./src/capabilities/workflow-engine').SequentialStep
993
+ );
994
+ this._engine.registerStepType(
995
+ require('./src/capabilities/workflow-engine').StepType.LOOP,
996
+ require('./src/capabilities/workflow-engine').LoopStep
997
+ );
998
+ this._engine.registerStepType(
999
+ require('./src/capabilities/workflow-engine').StepType.DELAY,
1000
+ require('./src/capabilities/workflow-engine').DelayStep
1001
+ );
1002
+ this._engine.registerStepType(
1003
+ require('./src/capabilities/workflow-engine').StepType.WORKFLOW,
1004
+ require('./src/capabilities/workflow-engine').NestedWorkflowStep
1005
+ );
1006
+ // 清除已注册的工具
1007
+ for (const toolName of this._workflowTools.values()) {
1008
+ // 工具注销需要框架支持,这里只清理内部状态
1009
+ }
1010
+ this._workflowTools.clear();
1011
+ this._workflows.clear();
1012
+ // 重新加载
1013
+ this._loadWorkflows();
1014
+ this._registerWorkflowTools();
1015
+ log.info(` Reloaded. Total workflows: ${this._workflows.size}`);
1016
+ }
1017
+ /**
1018
+ * 执行工作流
1019
+ */
1020
+ async executeWorkflow(workflowDef, input = {}, sessionId = null) {
1021
+ try {
1022
+ let workflow;
1023
+ if (typeof workflowDef === 'string') {
1024
+ // 尝试作为工作流名称加载(先检查是否已加载的工作流)
1025
+ const workflowName = workflowDef.trim();
1026
+ if (this._workflows.has(workflowName)) {
1027
+ workflow = this._workflows.get(workflowName);
1028
+ } else {
1029
+ // 尝试解析 JSON 或执行代码
1030
+ try {
1031
+ workflow = JSON.parse(workflowDef);
1032
+ } catch {
1033
+ // 使用沙箱解析工作流定义,防止恶意代码执行
1034
+ workflow = runWorkflowSafely(workflowDef, this._engine, { timeout: 5000 });
1035
+ }
1036
+ }
1037
+ } else {
1038
+ workflow = workflowDef;
1039
+ }
1040
+ const context = this._engine.createContext(input, {});
1041
+ // 将 sessionId 存储到上下文变量,供工具步骤使用
1042
+ if (sessionId) {
1043
+ context.variables._sessionId = sessionId;
1044
+ }
1045
+ // 执行工作流步骤
1046
+ if (workflow.steps && Array.isArray(workflow.steps)) {
1047
+ const results = [];
1048
+ // 按 id 存储步骤输出,供 ${id.output} 引用
1049
+ context.variables._stepOutputs = {};
1050
+ for (const stepConfig of workflow.steps) {
1051
+ const step = this._engine.createStep(stepConfig);
1052
+ const result = await step.execute(context, this._engine);
1053
+ results.push(result);
1054
+ // 如果步骤有 id,存储其输出
1055
+ if (stepConfig.id) {
1056
+ context.variables._stepOutputs[stepConfig.id] = result;
1057
+ }
1058
+ }
1059
+ // 只返回最后一步的结果(包含最终输出)和成功状态
1060
+ // 不返回所有中间结果,避免上下文超限
1061
+ const lastResult = results.length > 0 ? results[results.length - 1] : null;
1062
+ // context.variables 中提取非下划线开头的用户变量
1063
+ // 下划线开头的是内部变量(如 _stepOutputs),不需要返回
1064
+ const userVariables = {};
1065
+ for (const [key, value] of Object.entries(context.variables)) {
1066
+ if (!key.startsWith('_')) {
1067
+ userVariables[key] = value;
1068
+ }
1069
+ }
1070
+ return {
1071
+ success: true,
1072
+ stepCount: workflow.steps.length,
1073
+ result: lastResult,
1074
+ output: userVariables,
1075
+ };
1076
+ }
1077
+ return { success: true, output: {} };
1078
+ } catch (err) {
1079
+ return { success: false, error: err.message };
1080
+ }
1081
+ }
1082
+ /**
1083
+ * 获取引擎
1084
+ */
1085
+ getEngine() {
1086
+ return this._engine;
1087
+ }
1088
+ uninstall(framework) {
1089
+ this._engine = null;
1090
+ this._framework = null;
1091
+ }
1092
+ }
1093
+ module.exports = {
1094
+ WorkflowPlugin,
1095
+ WorkflowEngine,
1096
+ WorkflowStep,
1097
+ StepType,
1098
+ StepExecutor,
1099
+ ScriptStep,
1100
+ ConditionStep,
1101
+ ParallelStep,
1102
+ SwitchStep,
1103
+ TryStep,
1104
+ NestedWorkflowStep,
1105
+ SequentialStep,
1106
+ LoopStep,
1107
+ DelayStep,
1108
+ ToolStep,
1109
+ };