refactor: replace Moderator function with ModeratorTable in WorkflowDefinition #200

Closed
opened 2026-05-12 01:44:40 +00:00 by xingyue · 0 comments
Owner

RFC: ModeratorTable 替换 Moderator 函数

问题

当前 WorkflowDefinitionmoderator 字段是一个函数类型

type Moderator<M> = (ctx: ModeratorContext<M>) => (keyof M & string) | typeof END;

type WorkflowDefinition<M> = {
  description: string;
  roles: { ... };
  moderator: Moderator<M>;  // ← 函数,不可序列化
};

但实际上所有模板(developsolve-issuehello-template)都在用 ModeratorTable + tableToModerator() 转换:

const table: ModeratorTable<DevelopMeta> = {
  [START]: [{ condition: "FALLBACK", role: "planner" }],
  planner: [{ condition: "FALLBACK", role: "coder" }],
  // ...
};
export const developModerator = tableToModerator(table); // 包了一层

这导致两个问题:

  1. 信息丢失Moderator 是黑盒函数,无法序列化为静态图结构(#198 graph visualization 被阻塞)
  2. 概念冗余:protocol 层同时暴露 Moderator(函数)和 ModeratorTable(声明式),模板作者要先写 table 再手动调 tableToModerator(),多余一步

提议

WorkflowDefinition.moderator 从函数类型改为声明式 ModeratorTabletableToModerator 下沉到 engine 内部。

Before

protocol 暴露: Moderator (fn), ModeratorTable, tableToModerator
模板写法:      table → tableToModerator(table) → WorkflowDefinition.moderator
engine 消费:   def.moderator(ctx) 直接调用

After

protocol 暴露: ModeratorTable(声明式,可序列化)
engine 内部:   tableToModerator(def.table) 在 engine 层转换
模板写法:      table → WorkflowDefinition.table

具体改动

1. workflow-protocol 类型变更

// Before
type WorkflowDefinition<M extends RoleMeta> = {
  description: string;
  roles: { [K in keyof M & string]: RoleDefinition<M[K]> };
  moderator: Moderator<M>;
};

// After
type WorkflowDefinition<M extends RoleMeta> = {
  description: string;
  roles: { [K in keyof M & string]: RoleDefinition<M[K]> };
  table: ModeratorTable<M>;
};

2. workflow-protocol 导出变更

  • Moderator 类型 → 不再从 protocol/runtime 导出(移至 engine 内部类型)
  • tableToModerator → 不再从 protocol/runtime 导出(移至 engine 内部)
  • ModeratorTable, ModeratorTransition, ModeratorCondition → 保留导出

3. 模板改造

所有模板直接导出 table,不再调 tableToModerator()

// Before (develop/src/moderator.ts)
export const developModerator = tableToModerator(table);

// After
export { table as developTable };
// Before (develop/src/index.ts)
export const developWorkflowDefinition: WorkflowDefinition<DevelopMeta> = {
  ...
  moderator: developModerator,
};

// After
export const developWorkflowDefinition: WorkflowDefinition<DevelopMeta> = {
  ...
  table: developTable,
};

4. Engine 层适配

createWorkflow / advanceOnce 内部调 tableToModerator(def.table) 得到函数再执行。tableToModerator 仅作为 engine 内部工具函数。

5. buildDescriptor 自动提取 graph

WorkflowDefinition.table 是声明式数据 → buildDescriptor 可以直接遍历 table 提取 WorkflowGraph(#198 不再被阻塞)。

6. CLI init 模板更新

hello-template scaffold 改为直接写 ModeratorTable

影响范围

改动
workflow-protocol 类型变更 + 移除 Moderator / tableToModerator 导出
workflow-runtime re-export 同步更新
workflow-execute (engine) advanceOnce / createWorkflow 内部转换
workflow-template-develop moderator.ts 简化
workflow-template-solve-issue moderator.ts 简化
workflow-register buildDescriptor 支持 graph 提取
cli-workflow init 模板 + skill 文档更新

不变的

  • ModeratorCondition 仍可包含 check 函数 — table 里的 condition 是运行时对象,只是 name/description 可被静态提取
  • ModeratorContext 类型不变
  • Engine 执行语义不变(table 的求值顺序等完全一致)

关联

  • Unblocks #198 (Dashboard workflow graph visualization)
## RFC: ModeratorTable 替换 Moderator 函数 ### 问题 当前 `WorkflowDefinition` 的 `moderator` 字段是一个**函数类型**: ```ts type Moderator<M> = (ctx: ModeratorContext<M>) => (keyof M & string) | typeof END; type WorkflowDefinition<M> = { description: string; roles: { ... }; moderator: Moderator<M>; // ← 函数,不可序列化 }; ``` 但实际上所有模板(`develop`、`solve-issue`、`hello-template`)都在用 `ModeratorTable` + `tableToModerator()` 转换: ```ts const table: ModeratorTable<DevelopMeta> = { [START]: [{ condition: "FALLBACK", role: "planner" }], planner: [{ condition: "FALLBACK", role: "coder" }], // ... }; export const developModerator = tableToModerator(table); // 包了一层 ``` 这导致两个问题: 1. **信息丢失**:`Moderator` 是黑盒函数,无法序列化为静态图结构(#198 graph visualization 被阻塞) 2. **概念冗余**:protocol 层同时暴露 `Moderator`(函数)和 `ModeratorTable`(声明式),模板作者要先写 table 再手动调 `tableToModerator()`,多余一步 ### 提议 将 `WorkflowDefinition.moderator` 从函数类型改为声明式 `ModeratorTable`,`tableToModerator` 下沉到 engine 内部。 #### Before ``` protocol 暴露: Moderator (fn), ModeratorTable, tableToModerator 模板写法: table → tableToModerator(table) → WorkflowDefinition.moderator engine 消费: def.moderator(ctx) 直接调用 ``` #### After ``` protocol 暴露: ModeratorTable(声明式,可序列化) engine 内部: tableToModerator(def.table) 在 engine 层转换 模板写法: table → WorkflowDefinition.table ``` ### 具体改动 #### 1. `workflow-protocol` 类型变更 ```ts // Before type WorkflowDefinition<M extends RoleMeta> = { description: string; roles: { [K in keyof M & string]: RoleDefinition<M[K]> }; moderator: Moderator<M>; }; // After type WorkflowDefinition<M extends RoleMeta> = { description: string; roles: { [K in keyof M & string]: RoleDefinition<M[K]> }; table: ModeratorTable<M>; }; ``` #### 2. `workflow-protocol` 导出变更 - `Moderator` 类型 → 不再从 protocol/runtime 导出(移至 engine 内部类型) - `tableToModerator` → 不再从 protocol/runtime 导出(移至 engine 内部) - `ModeratorTable`, `ModeratorTransition`, `ModeratorCondition` → 保留导出 #### 3. 模板改造 所有模板直接导出 table,不再调 `tableToModerator()`: ```ts // Before (develop/src/moderator.ts) export const developModerator = tableToModerator(table); // After export { table as developTable }; ``` ```ts // Before (develop/src/index.ts) export const developWorkflowDefinition: WorkflowDefinition<DevelopMeta> = { ... moderator: developModerator, }; // After export const developWorkflowDefinition: WorkflowDefinition<DevelopMeta> = { ... table: developTable, }; ``` #### 4. Engine 层适配 `createWorkflow` / `advanceOnce` 内部调 `tableToModerator(def.table)` 得到函数再执行。`tableToModerator` 仅作为 engine 内部工具函数。 #### 5. `buildDescriptor` 自动提取 graph `WorkflowDefinition.table` 是声明式数据 → `buildDescriptor` 可以直接遍历 table 提取 `WorkflowGraph`(#198 不再被阻塞)。 #### 6. CLI init 模板更新 `hello-template` scaffold 改为直接写 `ModeratorTable`。 ### 影响范围 | 包 | 改动 | |---|---| | `workflow-protocol` | 类型变更 + 移除 `Moderator` / `tableToModerator` 导出 | | `workflow-runtime` | re-export 同步更新 | | `workflow-execute` (engine) | `advanceOnce` / `createWorkflow` 内部转换 | | `workflow-template-develop` | moderator.ts 简化 | | `workflow-template-solve-issue` | moderator.ts 简化 | | `workflow-register` | `buildDescriptor` 支持 graph 提取 | | `cli-workflow` | init 模板 + skill 文档更新 | ### 不变的 - `ModeratorCondition` 仍可包含 `check` 函数 — table 里的 condition 是运行时对象,只是 name/description 可被静态提取 - `ModeratorContext` 类型不变 - Engine 执行语义不变(table 的求值顺序等完全一致) ### 关联 - Unblocks #198 (Dashboard workflow graph visualization)
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: uncaged/workflow#200