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.
- package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
- package/.agent/ARCHITECTURE.md +288 -0
- package/.agent/agents/ambient-agent.md +57 -0
- package/.agent/agents/debugger.md +55 -0
- package/.agent/agents/email-assistant.md +49 -0
- package/.agent/agents/file-manager.md +42 -0
- package/.agent/agents/python-developer.md +60 -0
- package/.agent/agents/scheduler.md +59 -0
- package/.agent/agents/web-developer.md +45 -0
- package/.agent/data/default.json +29 -0
- package/.agent/data/plugins-state.json +255 -0
- package/.agent/mcp_config.json +4 -0
- package/.agent/mcp_config_updated.json +12 -0
- package/.agent/plugins.json +5 -0
- package/.agent/rules/GEMINI.md +273 -0
- package/.agent/rules/allow-rule.md +77 -0
- package/.agent/rules/log-rule.md +83 -0
- package/.agent/rules/security-rule.md +93 -0
- package/.agent/scripts/auto_preview.py +148 -0
- package/.agent/scripts/checklist.py +217 -0
- package/.agent/scripts/session_manager.py +120 -0
- package/.agent/scripts/verify_all.py +327 -0
- package/.agent/skills/api-patterns/SKILL.md +81 -0
- package/.agent/skills/api-patterns/api-style.md +42 -0
- package/.agent/skills/api-patterns/auth.md +24 -0
- package/.agent/skills/api-patterns/documentation.md +26 -0
- package/.agent/skills/api-patterns/graphql.md +41 -0
- package/.agent/skills/api-patterns/rate-limiting.md +31 -0
- package/.agent/skills/api-patterns/response.md +37 -0
- package/.agent/skills/api-patterns/rest.md +40 -0
- package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
- package/.agent/skills/api-patterns/security-testing.md +122 -0
- package/.agent/skills/api-patterns/trpc.md +41 -0
- package/.agent/skills/api-patterns/versioning.md +22 -0
- package/.agent/skills/app-builder/SKILL.md +75 -0
- package/.agent/skills/app-builder/agent-coordination.md +71 -0
- package/.agent/skills/app-builder/feature-building.md +53 -0
- package/.agent/skills/app-builder/project-detection.md +34 -0
- package/.agent/skills/app-builder/scaffolding.md +118 -0
- package/.agent/skills/app-builder/tech-stack.md +40 -0
- package/.agent/skills/app-builder/templates/SKILL.md +39 -0
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
- package/.agent/skills/architecture/SKILL.md +55 -0
- package/.agent/skills/architecture/context-discovery.md +43 -0
- package/.agent/skills/architecture/examples.md +94 -0
- package/.agent/skills/architecture/pattern-selection.md +68 -0
- package/.agent/skills/architecture/patterns-reference.md +50 -0
- package/.agent/skills/architecture/trade-off-analysis.md +77 -0
- package/.agent/skills/clean-code/SKILL.md +201 -0
- package/.agent/skills/doc.md +177 -0
- package/.agent/skills/frontend-design/SKILL.md +418 -0
- package/.agent/skills/frontend-design/animation-guide.md +331 -0
- package/.agent/skills/frontend-design/color-system.md +311 -0
- package/.agent/skills/frontend-design/decision-trees.md +418 -0
- package/.agent/skills/frontend-design/motion-graphics.md +306 -0
- package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
- package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
- package/.agent/skills/frontend-design/typography-system.md +345 -0
- package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
- package/.agent/skills/frontend-design/visual-effects.md +383 -0
- package/.agent/skills/i18n-localization/SKILL.md +154 -0
- package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
- package/.agent/skills/mcp-builder/SKILL.md +176 -0
- package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
- package/.agent/workflows/brainstorm.md +113 -0
- package/.agent/workflows/create.md +59 -0
- package/.agent/workflows/debug.md +103 -0
- package/.agent/workflows/deploy.md +176 -0
- package/.agent/workflows/enhance.md +63 -0
- package/.agent/workflows/orchestrate.md +237 -0
- package/.agent/workflows/plan.md +89 -0
- package/.agent/workflows/preview.md +81 -0
- package/.agent/workflows/simple-test.md +42 -0
- package/.agent/workflows/status.md +86 -0
- package/.agent/workflows/structured-orchestrate.md +180 -0
- package/.agent/workflows/test.md +144 -0
- package/.agent/workflows/ui-ux-pro-max.md +296 -0
- package/.claude/settings.local.json +11 -1
- package/.editorconfig +56 -0
- package/.husky/pre-commit +4 -0
- package/.lintstagedrc +7 -0
- package/.prettierignore +29 -0
- package/.prettierrc +11 -0
- package/CLAUDE.md +2 -0
- package/README.md +64 -55
- package/SPEC.md +102 -61
- package/cli/bin/foliko.js +11 -11
- package/cli/src/commands/chat.js +143 -141
- package/cli/src/commands/list.js +93 -90
- package/cli/src/index.js +75 -75
- package/cli/src/ui/chat-ui.js +201 -199
- package/cli/src/utils/ansi.js +40 -40
- package/cli/src/utils/markdown.js +292 -296
- package/docker-compose.yml +1 -1
- package/docs/ai-sdk-optimization.md +655 -643
- package/docs/features.md +80 -80
- package/docs/quick-reference.md +49 -46
- package/docs/user-manual.md +411 -380
- package/examples/ambient-example.js +194 -196
- package/examples/basic.js +50 -45
- package/examples/bootstrap.js +121 -112
- package/examples/mcp-example.js +19 -16
- package/examples/skill-example.js +20 -20
- package/examples/test-chat.js +137 -135
- package/examples/test-mcp.js +85 -79
- package/examples/test-reload.js +59 -61
- package/examples/test-telegram.js +50 -50
- package/examples/test-tg-bot.js +45 -42
- package/examples/test-tg-simple.js +47 -46
- package/examples/test-tg.js +62 -62
- package/examples/test-think.js +43 -37
- package/examples/test-web-plugin.js +103 -98
- package/examples/test-weixin-feishu.js +103 -100
- package/examples/workflow.js +158 -158
- package/package.json +37 -3
- package/plugins/ai-plugin.js +102 -100
- package/plugins/ambient-agent/EventWatcher.js +113 -0
- package/plugins/ambient-agent/ExplorerLoop.js +640 -0
- package/plugins/ambient-agent/GoalManager.js +197 -0
- package/plugins/ambient-agent/Reflector.js +95 -0
- package/plugins/ambient-agent/StateStore.js +90 -0
- package/plugins/ambient-agent/constants.js +101 -0
- package/plugins/ambient-agent/index.js +579 -0
- package/plugins/audit-plugin.js +187 -187
- package/plugins/default-plugins.js +662 -649
- package/plugins/email/constants.js +64 -0
- package/plugins/email/handlers.js +461 -0
- package/plugins/email/index.js +278 -0
- package/plugins/email/monitor.js +269 -0
- package/plugins/email/parser.js +138 -0
- package/plugins/email/reply.js +151 -0
- package/plugins/email/utils.js +124 -0
- package/plugins/feishu-plugin.js +481 -477
- package/plugins/file-system-plugin.js +826 -476
- package/plugins/install-plugin.js +199 -197
- package/plugins/python-executor-plugin.js +367 -365
- package/plugins/python-plugin-loader.js +481 -479
- package/plugins/rules-plugin.js +294 -292
- package/plugins/scheduler-plugin.js +691 -689
- package/plugins/session-plugin.js +369 -367
- package/plugins/shell-executor-plugin.js +197 -197
- package/plugins/storage-plugin.js +240 -238
- package/plugins/subagent-plugin.js +845 -785
- package/plugins/telegram-plugin.js +482 -475
- package/plugins/think-plugin.js +345 -343
- package/plugins/tools-plugin.js +196 -194
- package/plugins/web-plugin.js +606 -604
- package/plugins/weixin-plugin.js +545 -538
- package/reports/system-health-report-20260401.md +79 -0
- package/skills/ambient-agent/SKILL.md +49 -39
- package/skills/foliko-dev/AGENTS.md +64 -61
- package/skills/foliko-dev/SKILL.md +125 -119
- package/skills/mcp-usage/SKILL.md +19 -17
- package/skills/python-plugin-dev/SKILL.md +16 -15
- package/skills/skill-guide/SKILL.md +12 -12
- package/skills/subagent-guide/SKILL.md +237 -0
- package/skills/workflow-guide/SKILL.md +90 -45
- package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
- package/skills/workflow-troubleshooting/SKILL.md +156 -79
- package/src/capabilities/index.js +11 -11
- package/src/capabilities/skill-manager.js +609 -595
- package/src/capabilities/workflow-engine.js +1109 -1195
- package/src/core/agent-chat.js +882 -735
- package/src/core/agent.js +892 -688
- package/src/core/framework.js +465 -431
- package/src/core/index.js +19 -19
- package/src/core/plugin-base.js +219 -219
- package/src/core/plugin-manager.js +863 -767
- package/src/core/provider.js +114 -111
- package/src/core/sub-agent-config.js +264 -0
- package/src/core/system-prompt-builder.js +120 -0
- package/src/core/tool-registry.js +517 -134
- package/src/core/tool-router.js +297 -216
- package/src/executors/executor-base.js +12 -12
- package/src/executors/mcp-executor.js +741 -729
- package/src/index.js +25 -37
- package/src/utils/circuit-breaker.js +301 -0
- package/src/utils/error-boundary.js +363 -0
- package/src/utils/error.js +374 -0
- package/src/utils/event-emitter.js +97 -97
- package/src/utils/id.js +133 -0
- package/src/utils/index.js +217 -3
- package/src/utils/logger.js +181 -0
- package/src/utils/plugin-helpers.js +90 -0
- package/src/utils/retry.js +122 -0
- package/src/utils/sandbox.js +292 -0
- package/test/tool-registry-validation.test.js +218 -0
- package/test_report.md +70 -0
- package/website/docs/api.html +169 -107
- package/website/docs/configuration.html +296 -144
- package/website/docs/plugin-development.html +154 -85
- package/website/docs/project-structure.html +110 -109
- package/website/docs/skill-development.html +117 -61
- package/website/index.html +209 -205
- package/website/script.js +136 -133
- package/website/styles.css +1 -1
- package/plugins/ambient-agent-plugin.js +0 -1565
- package/plugins/email.js +0 -1142
|
@@ -1,1195 +1,1109 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WorkflowEngine 工作流引擎
|
|
3
|
-
* 支持结构化工作流定义和执行
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
*
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
[StepType.
|
|
71
|
-
[StepType.
|
|
72
|
-
[StepType.
|
|
73
|
-
[StepType.
|
|
74
|
-
[StepType.
|
|
75
|
-
[StepType.
|
|
76
|
-
[StepType.
|
|
77
|
-
[StepType.
|
|
78
|
-
[StepType.
|
|
79
|
-
[StepType.
|
|
80
|
-
[StepType.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
*
|
|
166
|
-
*/
|
|
167
|
-
async
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
return
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
async execute(context, engine) {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
}
|
|
569
|
-
return
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
this.
|
|
580
|
-
this.
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
this.
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
/**
|
|
811
|
-
*
|
|
812
|
-
*/
|
|
813
|
-
class
|
|
814
|
-
constructor(
|
|
815
|
-
super()
|
|
816
|
-
this.
|
|
817
|
-
this.
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
this.
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
framework
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
this.
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
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
|
+
};
|