## 如何使用 FlowLab (统一设计版) - 中文自然语言描述

FlowLab 是一个用来帮助你定义、执行和管理复杂任务流程（工作流）的 TypeScript/JavaScript 库。它特别适合处理那些包含多个步骤、需要条件判断、可能需要重试或与其他系统交互的业务逻辑。以下是如何使用这个新版 FlowLab 库的基本步骤：

**第一步：初始化 FlowLab 引擎**

首先，你需要创建一个 `FlowLabEngine` 的实例。这是你与 FlowLab 交互的主要入口。

```typescript
import { FlowLabEngine, ConsoleLogger } from './flowlab/src'; // 假设你的库代码在 flowlab/src

// 创建引擎实例，可以传入配置选项
const engine = new FlowLabEngine({
  logger: new ConsoleLogger('[MyWorkflowApp]'), // 使用控制台打印日志
  // 如果需要持久化工作流状态（比如长时间运行的流程或故障恢复），可以配置持久化服务
  // persistence: new MemoryPersistence(), // 使用内存持久化 (适合开发测试)
  // persistence: new RedisPersistence('redis://...'), // 或使用 Redis (适合生产)
  // 如果需要延迟执行或分布式任务，可以配置调度器和事件管理器
  // scheduler: new LocalScheduler(...),
  // eventManager: new InMemoryEventManager(),
});
```

引擎会管理所有的节点、工作流定义以及配置。你可以在创建时传入自定义的日志记录器、
持久化存储方案、任务调度器和事件管理器，如果省略，它会使用一些默认的简单实现（比如打印日志到控制台）。

**第二步：定义你的任务节点 (Node)**

工作流中的每个具体操作（比如调用 API、查询数据库、处理数据、调用 AI 模型等）都需要定义为一个“节点”。你有两种方式定义节点：

1.  **简单函数节点 (适用于简单、无状态的任务):**
    直接注册一个异步函数。函数会接收一个 `context` 对象作为参数，你可以通过 `context.input` 获取输入，通过 `context.output = ...` 设置输出，或者通过 `context.getVariable`/`setVariable` 读写工作流变量。

    ```typescript
    // 注册一个名为 'fetch-user' 的节点
    engine.registerNode('fetch-user', async (context) => {
      const userId = context.input.id;
      context.log(`正在获取用户 ${userId} 的数据...`);
      // 模拟 API 调用
      await new Promise(res => setTimeout(res, 100));
      // 将结果设置到输出
      context.output = { name: `用户${userId}`, email: `${userId}@example.com` };
    }, '获取用户信息的节点'); // 可以加个描述
    ```

2.  **基于类的节点 (适用于复杂、有状态、需要验证或补偿逻辑的任务):**
    创建一个类，让它继承自 `BaseNode`，并实现 `metadata` (包含节点 ID) 和 `execute` 方法。这种方式更结构化，适合封装复杂的逻辑。

    ```typescript
    import { BaseNode, INodeContext, NodeStatus } from './flowlab/src';

    class ProcessDataNode extends BaseNode {
      // 定义节点元数据 (ID 必须)
      readonly metadata = { id: 'process-data', description: '处理用户分数' };

      // 实现核心执行逻辑
      async execute(context: INodeContext): Promise<void> {
        const score = context.input.score;
        context.log(`处理分数: ${score}`);
        const level = score > 80 ? '优秀' : score > 60 ? '良好' : '一般';
        context.output = { level }; // 设置输出
        context.setVariable('userLevel', level); // 设置工作流变量
      }

      // (可选) 实现输入验证
      validate(context: INodeContext): void {
        if (typeof context.input.score !== 'number') {
          throw new Error('输入分数必须是数字'); // 抛出错误会使节点执行失败
        }
      }

      // (可选) 实现补偿逻辑 (如果需要回滚)
      // async compensate(context: INodeContext): Promise<void> { ... }
    }

    // 注册节点类的实例
    engine.registerNode(new ProcessDataNode());
    ```

**第三步：定义你的工作流 (Workflow Definition)**

使用 `engine.defineWorkflow('工作流ID')` 开始定义一个工作流，然后通过链式调用添加各种步骤：

* **`addStep(config)`:** 添加一个执行节点的任务步骤。你需要提供步骤 `id`、要执行的 `nodeId`，以及可选的 `nextStepId`（下一步）、`input`（静态输入）、`inputMapping`（动态输入映射）、`outputMapping`（输出映射）、`retryOptions`（重试配置）、`timeoutMs`（超时）。
* **`addCondition(config)`:** 添加一个条件分支步骤。你需要提供 `id`、一个返回布尔值或分支名称的 `condition` 函数，以及一个 `branches` 对象，将条件结果映射到不同的 `nextStepId`。
* **`addParallel(config)`:** 添加一个并行步骤。`parallelSteps` 数组里包含需要并行执行的步骤配置。`nextStepId` 指向所有并行分支完成后执行的步骤。
* **`addSubWorkflow(config)`:** 添加一个子工作流步骤。需要提供 `subWorkflowId`（要调用的子流程 ID）。
* **`setStartStep('步骤ID')`:** 指定工作流从哪个步骤开始执行。

```typescript
// 定义一个工作流
const definition = engine.defineWorkflow('user-approval', '用户审批流程')
  .addStep({ // 第一个任务步骤
    id: 'fetch',
    nodeId: 'fetch-user', // 执行我们上面注册的函数节点
    inputMapping: { 'id': 'input.userId' }, // 将工作流初始输入的 userId 映射给节点的 id 输入
    nextStepId: 'process' // 下一步是 process
  })
  .addStep({ // 第二个任务步骤
    id: 'process',
    nodeId: 'process-data', // 执行我们上面注册的类节点
    inputMapping: { 'score': 'steps.fetch.output.score' }, // 假设 fetch-user 节点输出score
    // 注意: steps.stepId.output 映射需要引擎实现支持
    // 更可靠的方式是在 fetch 步骤用 outputMapping 将 score 存入变量
    // 例如: outputMapping: { 'variables.currentScore': 'output.score' }
    // 然后这里用: inputMapping: { 'score': 'variables.currentScore' }
    outputMapping: { 'variables.finalLevel': 'output.level' }, // 将 process-data 的输出 level 存入变量 finalLevel
    nextStepId: 'checkLevel' // 下一步是 checkLevel
  })
  .addCondition({ // 条件步骤
    id: 'checkLevel',
    condition: (context) => context.variables.finalLevel === '优秀', // 检查变量 finalLevel
    branches: {
      'true': 'autoApprove', // 如果是'优秀', 跳到 autoApprove
      'false': 'manualReview' // 否则跳到 manualReview
    }
  })
  .addStep({ // '优秀'分支的目标步骤
    id: 'autoApprove',
    nodeId: 'simple-log', // 用一个日志节点模拟自动批准
    input: { message: '用户自动批准！' }
    // 这个分支结束
  })
  .addStep({ // '非优秀'分支的目标步骤
    id: 'manualReview',
    nodeId: 'simple-log', // 用日志节点模拟人工审核
    input: { message: '用户需要人工审核。' }
    // 这个分支也结束
  })
  .setStartStep('fetch'); // 设置 'fetch' 为起始步骤

// (可选) 如果希望通过 ID 执行或持久化这个定义，需要显式注册
engine.registerDefinition(definition);
```

**第四步：执行工作流**

工作流定义好之后，你需要创建一个 `WorkflowExecutor` 来执行它。

1.  **创建执行器:**
    ```typescript
    const executor = engine.createExecutor();
    ```

2.  **运行工作流:**
    你可以通过**工作流定义实例**或**注册的 ID**来运行。

    ```typescript
    // 定义初始输入数据
    const initialData = { userId: 'abc-123' };

    // 定义附加的上下文信息 (可选)
    const contextExtras = { tenantId: 'my-company', userRole: 'operator' };

    // 运行方式一：使用 WorkflowDefinition 实例
    // const resultContext = await executor.run(definition, initialData, contextExtras);

    // 运行方式二：使用注册的 ID (前提是已调用 engine.registerDefinition)
    const resultContext = await executor.runById('user-approval', initialData, contextExtras);

    // 检查最终结果
    console.log('工作流最终状态:', resultContext.status); // e.g., COMPLETED, FAILED
    console.log('工作流最终输出:', resultContext.output); // 工作流的最终输出 (如果有)
    console.log('工作流最终变量:', resultContext.variables); // 所有工作流变量的最终值
    // console.log('工作流执行历史:', resultContext.history); // 查看详细步骤历史
    ```

3.  **(快捷方式) `engine.runWorkflow(...)`:** 对于简单的、一次性的流程，可以直接用这个方法，它会帮你临时创建定义并执行。

    ```typescript
    const simpleResult = await engine.runWorkflow(
      (wf) => { // 在回调里定义流程
        wf.addStep({ id: 'log', nodeId: 'simple-log', input: { message: '快捷执行！' } })
          .setStartStep('log');
      },
      {} // 初始输入
    );
    console.log('快捷流程状态:', simpleResult.status);
    ```

**核心概念总结:**

* **Engine (引擎):** 管理一切的中心。
* **Node (节点):** 执行具体任务的单元 (函数或类)。
* **Workflow Definition (工作流定义):** 描述任务流程的蓝图 (步骤、连接、条件)。
* **Workflow Instance (工作流实例):** 一次具体的执行过程，有自己的 ID、状态、变量和历史。
* **Executor (执行器):** 负责根据定义运行实例。
* **Context (上下文):** 存储实例的运行时数据 (输入、变量、状态、日志等)。
* **Mapping (映射):** 控制数据如何在工作流变量和节点输入/输出之间流动的关键机制。

通过以上步骤，你就可以使用 FlowLab 来构建、管理和执行你的业务流程了。对于更复杂的场景，你可以深入研究并行处理、子流程、事件驱动、持久化和调度等高级功能。