foliko 1.0.63 → 1.0.65

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.
@@ -20,6 +20,7 @@ const StepType = {
20
20
  SEQUENTIAL: 'sequential',
21
21
  LOOP: 'loop',
22
22
  DELAY: 'delay',
23
+ TOOL: 'tool',
23
24
  INPUT: 'input',
24
25
  OUTPUT: 'output'
25
26
  }
@@ -244,6 +245,112 @@ class DelayStep extends WorkflowStep {
244
245
  }
245
246
  }
246
247
 
248
+ /**
249
+ * 工具步骤
250
+ */
251
+ class ToolStep extends WorkflowStep {
252
+ constructor(config) {
253
+ super({ ...config, type: StepType.TOOL })
254
+ this.tool = config.tool
255
+ this.args = config.args || {}
256
+ this.outputVariable = config.outputVariable || null
257
+ }
258
+
259
+ async execute(context, engine) {
260
+ if (!this.tool) {
261
+ throw new Error('Tool step requires a tool name')
262
+ }
263
+
264
+ console.log(`[Workflow] Executing tool: ${this.tool}`)
265
+
266
+ // 解析工具参数,支持变量引用
267
+ const resolvedArgs = this._resolveArgs(this.args, context)
268
+
269
+ // 获取当前 sessionId(从上下文变量或执行上下文)
270
+ let sessionId = context.variables._sessionId
271
+ if (!sessionId && engine.framework.getExecutionContext) {
272
+ const ctx = engine.framework.getExecutionContext()
273
+ sessionId = ctx?.sessionId
274
+ }
275
+
276
+ // 使用 sessionId 上下文执行工具
277
+ let result
278
+ if (sessionId && engine.framework.runWithContext) {
279
+ result = await engine.framework.runWithContext(
280
+ { sessionId },
281
+ async () => await engine.framework.executeTool(this.tool, resolvedArgs)
282
+ )
283
+ } else {
284
+ result = await engine.framework.executeTool(this.tool, resolvedArgs)
285
+ }
286
+
287
+ // 保存结果到变量
288
+ if (this.outputVariable) {
289
+ context.variables[this.outputVariable] = result
290
+ }
291
+ context.lastResult = result
292
+
293
+ // 检查工具执行结果
294
+ if (result && result.error) {
295
+ console.warn(`[Workflow] Tool ${this.tool} returned error: ${result.error}`)
296
+ }
297
+
298
+ return result
299
+ }
300
+
301
+ /**
302
+ * 解析参数中的变量引用
303
+ * 支持 {{variableName}} 语法
304
+ */
305
+ _resolveArgs(args, context) {
306
+ const resolved = {}
307
+ for (const [key, value] of Object.entries(args)) {
308
+ resolved[key] = this._resolveValue(value, context)
309
+ }
310
+ return resolved
311
+ }
312
+
313
+ _resolveValue(value, context) {
314
+ if (typeof value === 'string') {
315
+ // 替换 {{variable}} 或 {{variables.name}} 语法
316
+ return value.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
317
+ // 支持 variables.xxx 或直接 xxx 格式
318
+ if (path.startsWith('variables.')) {
319
+ return this._getNestedValue(context, path) ?? match
320
+ } else if (path.startsWith('context.')) {
321
+ return this._getNestedValue(context, path) ?? match
322
+ } else {
323
+ // 尝试从 context.variables 获取
324
+ const val = this._getNestedValue(context.variables, path)
325
+ if (val !== undefined) return val
326
+ // 尝试从 context 直接获取
327
+ return this._getNestedValue(context, path) ?? match
328
+ }
329
+ })
330
+ } else if (Array.isArray(value)) {
331
+ return value.map(v => this._resolveValue(v, context))
332
+ } else if (typeof value === 'object' && value !== null) {
333
+ const resolved = {}
334
+ for (const [k, v] of Object.entries(value)) {
335
+ resolved[k] = this._resolveValue(v, context)
336
+ }
337
+ return resolved
338
+ }
339
+ return value
340
+ }
341
+
342
+ _getNestedValue(obj, path) {
343
+ if (!obj) return undefined
344
+ const parts = path.split('.')
345
+ let current = obj
346
+ for (const part of parts) {
347
+ if (current === null || current === undefined) return undefined
348
+ current = current[part]
349
+ }
350
+ return current
351
+ }
352
+ }
353
+
247
354
  /**
248
355
  * 工作流引擎
249
356
  */
@@ -316,6 +423,7 @@ class WorkflowPlugin extends Plugin {
316
423
  this._engine.registerStepType(StepType.SEQUENTIAL, SequentialStep)
317
424
  this._engine.registerStepType(StepType.LOOP, LoopStep)
318
425
  this._engine.registerStepType(StepType.DELAY, DelayStep)
426
+ this._engine.registerStepType(StepType.TOOL, ToolStep)
319
427
 
320
428
  // 注册工作流执行工具
321
429
  framework.registerTool({
@@ -325,8 +433,14 @@ class WorkflowPlugin extends Plugin {
325
433
  workflow: z.string().describe('工作流定义(JSON 或 JavaScript 代码)'),
326
434
  input: z.object({}).optional().describe('工作流输入参数')
327
435
  }),
328
- execute: async (args) => {
329
- return await this.executeWorkflow(args.workflow, args.input || {})
436
+ execute: async (args, framework) => {
437
+ // 获取当前 sessionId
438
+ let sessionId = null
439
+ const ctx = framework.getExecutionContext()
440
+ if (ctx?.sessionId) {
441
+ sessionId = ctx.sessionId
442
+ }
443
+ return await this.executeWorkflow(args.workflow, args.input || {}, sessionId)
330
444
  }
331
445
  })
332
446
 
@@ -455,18 +569,24 @@ class WorkflowPlugin extends Plugin {
455
569
  /**
456
570
  * 执行工作流
457
571
  */
458
- async executeWorkflow(workflowDef, input = {}) {
572
+ async executeWorkflow(workflowDef, input = {}, sessionId = null) {
459
573
  try {
460
574
  let workflow
461
575
 
462
576
  if (typeof workflowDef === 'string') {
463
- // 尝试解析 JSON 或执行代码
464
- try {
465
- workflow = JSON.parse(workflowDef)
466
- } catch {
467
- // eslint-disable-next-line no-new-func
468
- const fn = new Function('engine', 'return (' + workflowDef + ')')
469
- workflow = fn(this._engine)
577
+ // 尝试作为工作流名称加载(先检查是否已加载的工作流)
578
+ const workflowName = workflowDef.trim()
579
+ if (this._workflows.has(workflowName)) {
580
+ workflow = this._workflows.get(workflowName)
581
+ } else {
582
+ // 尝试解析 JSON 或执行代码
583
+ try {
584
+ workflow = JSON.parse(workflowDef)
585
+ } catch {
586
+ // eslint-disable-next-line no-new-func
587
+ const fn = new Function('engine', 'return (' + workflowDef + ')')
588
+ workflow = fn(this._engine)
589
+ }
470
590
  }
471
591
  } else {
472
592
  workflow = workflowDef
@@ -474,6 +594,11 @@ class WorkflowPlugin extends Plugin {
474
594
 
475
595
  const context = this._engine.createContext(input, {})
476
596
 
597
+ // 将 sessionId 存储到上下文变量,供工具步骤使用
598
+ if (sessionId) {
599
+ context.variables._sessionId = sessionId
600
+ }
601
+
477
602
  // 执行工作流步骤
478
603
  if (workflow.steps && Array.isArray(workflow.steps)) {
479
604
  const results = []
@@ -513,5 +638,6 @@ module.exports = {
513
638
  ConditionStep,
514
639
  SequentialStep,
515
640
  LoopStep,
516
- DelayStep
641
+ DelayStep,
642
+ ToolStep
517
643
  }
@@ -1,58 +1,58 @@
1
- /**
2
- * Executor 基类
3
- * 执行器的基类,定义执行器接口
4
- */
5
-
6
- const { EventEmitter } = require('../utils/event-emitter')
7
-
8
- class ExecutorBase extends EventEmitter {
9
- /**
10
- * @param {string} name - 执行器名称
11
- */
12
- constructor(name) {
13
- super()
14
- this.name = name
15
- this._enabled = true
16
- }
17
-
18
- /**
19
- * 执行
20
- * @param {Object} params - 执行参数
21
- * @returns {Promise<any>}
22
- */
23
- async execute(params) {
24
- throw new Error('execute() must be implemented')
25
- }
26
-
27
- /**
28
- * 启用执行器
29
- */
30
- enable() {
31
- this._enabled = true
32
- return this
33
- }
34
-
35
- /**
36
- * 禁用执行器
37
- */
38
- disable() {
39
- this._enabled = false
40
- return this
41
- }
42
-
43
- /**
44
- * 是否启用
45
- */
46
- isEnabled() {
47
- return this._enabled
48
- }
49
-
50
- /**
51
- * 销毁
52
- */
53
- destroy() {
54
- this.removeAllListeners()
55
- }
56
- }
57
-
58
- module.exports = { ExecutorBase }
1
+ /**
2
+ * Executor 基类
3
+ * 执行器的基类,定义执行器接口
4
+ */
5
+
6
+ const { EventEmitter } = require('../utils/event-emitter')
7
+
8
+ class ExecutorBase extends EventEmitter {
9
+ /**
10
+ * @param {string} name - 执行器名称
11
+ */
12
+ constructor(name) {
13
+ super()
14
+ this.name = name
15
+ this._enabled = true
16
+ }
17
+
18
+ /**
19
+ * 执行
20
+ * @param {Object} params - 执行参数
21
+ * @returns {Promise<any>}
22
+ */
23
+ async execute(params) {
24
+ throw new Error('execute() must be implemented')
25
+ }
26
+
27
+ /**
28
+ * 启用执行器
29
+ */
30
+ enable() {
31
+ this._enabled = true
32
+ return this
33
+ }
34
+
35
+ /**
36
+ * 禁用执行器
37
+ */
38
+ disable() {
39
+ this._enabled = false
40
+ return this
41
+ }
42
+
43
+ /**
44
+ * 是否启用
45
+ */
46
+ isEnabled() {
47
+ return this._enabled
48
+ }
49
+
50
+ /**
51
+ * 销毁
52
+ */
53
+ destroy() {
54
+ this.removeAllListeners()
55
+ }
56
+ }
57
+
58
+ module.exports = { ExecutorBase }
package/test-server.js CHANGED
@@ -1,25 +1,25 @@
1
- const { serve } = require('@hono/node-server');
2
- const { Hono } = require('hono');
3
-
4
- const app = new Hono();
5
-
6
- // 简单路由
7
- app.get('/test', (c) => {
8
- console.log('Handler called');
9
- return c.json({ message: 'Hello World' });
10
- });
11
-
12
- const server = serve({
13
- fetch: app.fetch,
14
- port: 3001
15
- });
16
-
17
- server.on('request', (req) => {
18
- console.log('Request:', req.method, req.url);
19
- });
20
-
21
- server.on('error', (err) => {
22
- console.error('Server error:', err);
23
- });
24
-
25
- console.log('Server started on port 3001');
1
+ const { serve } = require('@hono/node-server');
2
+ const { Hono } = require('hono');
3
+
4
+ const app = new Hono();
5
+
6
+ // 简单路由
7
+ app.get('/test', (c) => {
8
+ console.log('Handler called');
9
+ return c.json({ message: 'Hello World' });
10
+ });
11
+
12
+ const server = serve({
13
+ fetch: app.fetch,
14
+ port: 3001
15
+ });
16
+
17
+ server.on('request', (req) => {
18
+ console.log('Request:', req.method, req.url);
19
+ });
20
+
21
+ server.on('error', (err) => {
22
+ console.error('Server error:', err);
23
+ });
24
+
25
+ console.log('Server started on port 3001');
package/test.txt CHANGED
@@ -1,3 +1,3 @@
1
- Hello from static resource test!
2
- This is a test file for verifying static resource serving.
3
- Timestamp: 2026-03-24
1
+ Hello from static resource test!
2
+ This is a test file for verifying static resource serving.
3
+ Timestamp: 2026-03-24