refactor: 拆分 workflow 为七个独立包(protocol / runtime / util / cas / reactor / register / execute) #143

Closed
opened 2026-05-09 02:45:06 +00:00 by xingyue · 2 comments
Owner

What

将当前的 @uncaged/workflow 单包拆分为七个职责清晰的独立包。

Why

当前 workflow 包有 8 个模块、50 个源文件、80+ 公共 API 符号,模块间依赖关系复杂,engine 模块作为枢纽依赖了 6 个其他模块。按 SRP 分析,整个包对外其实只有两个核心能力:注册 bundle执行 workflow,加上被两侧共用的基础设施。

此外存在 config ↔ registry 循环依赖问题,需要通过提取 protocol 层解决。

目标架构

┌──────────┐  ┌──────────┐
│ register │  │ execute  │
└──┬────┬──┘  └──┬───┬───┘
   │    │        │   │
   │ ┌──▼────────▼┐ │
   │ │    cas     │ │
   │ └────────────┘ │
   │    ┌───────────▼─┐
   │    │   reactor   │
   │    └──────┬──────┘
   └─────┬─────┘
   ┌─────▼─────┐  ┌─────────┐
   │   util    │  │ runtime │
   └─────┬─────┘  └────┬────┘
         └──────┬───────┘
          ┌─────▼─────┐
          │ protocol  │
          └───────────┘

Phase 拆分

Phase Testing Issue 状态
1 @uncaged/workflow-protocol #144 🔲
2 @uncaged/workflow-util #145 🔲
3 @uncaged/workflow-runtime 重构 #146 🔲
4 @uncaged/workflow-cas #147 🔲
5 @uncaged/workflow-reactor #148 🔲
6 @uncaged/workflow-register #149 🔲
7 @uncaged/workflow-execute + CLI #150 🔲

完成标准

  • 所有 Phase 的 testing issue 已 close
  • 全局 bun run check 通过
  • 依赖图单向无环

Ref

基于 workflow 包架构讨论 + 小橘 review 意见(循环依赖、reactor 独立、命名风格)。

## What 将当前的 `@uncaged/workflow` 单包拆分为七个职责清晰的独立包。 ## Why 当前 workflow 包有 8 个模块、50 个源文件、80+ 公共 API 符号,模块间依赖关系复杂,engine 模块作为枢纽依赖了 6 个其他模块。按 SRP 分析,整个包对外其实只有两个核心能力:**注册 bundle** 和 **执行 workflow**,加上被两侧共用的基础设施。 此外存在 config ↔ registry 循环依赖问题,需要通过提取 protocol 层解决。 ## 目标架构 ``` ┌──────────┐ ┌──────────┐ │ register │ │ execute │ └──┬────┬──┘ └──┬───┬───┘ │ │ │ │ │ ┌──▼────────▼┐ │ │ │ cas │ │ │ └────────────┘ │ │ ┌───────────▼─┐ │ │ reactor │ │ └──────┬──────┘ └─────┬─────┘ ┌─────▼─────┐ ┌─────────┐ │ util │ │ runtime │ └─────┬─────┘ └────┬────┘ └──────┬───────┘ ┌─────▼─────┐ │ protocol │ └───────────┘ ``` ## Phase 拆分 | Phase | 包 | Testing Issue | 状态 | |---|---|---|---| | 1 | `@uncaged/workflow-protocol` | #144 | 🔲 | | 2 | `@uncaged/workflow-util` | #145 | 🔲 | | 3 | `@uncaged/workflow-runtime` 重构 | #146 | 🔲 | | 4 | `@uncaged/workflow-cas` | #147 | 🔲 | | 5 | `@uncaged/workflow-reactor` | #148 | 🔲 | | 6 | `@uncaged/workflow-register` | #149 | 🔲 | | 7 | `@uncaged/workflow-execute` + CLI | #150 | 🔲 | ## 完成标准 - [ ] 所有 Phase 的 testing issue 已 close - [ ] 全局 `bun run check` 通过 - [ ] 依赖图单向无环 ## Ref 基于 workflow 包架构讨论 + 小橘 review 意见(循环依赖、reactor 独立、命名风格)。
Owner

Review 意见 — 小橘 🍊(NEKO Team)

方向 ,SRP 拆分合理。跑了一遍实际的模块依赖图,几个发现和建议:

实际依赖图

util        ← 零依赖
cas         ← util
reactor     ← util
bundle      ← util
registry    ← util, config
config      ← util, registry  ⚠️
extract     ← util, cas, reactor
engine      ← util, cas, config, bundle, extract, reactor, registry

1. ⚠️ config ↔ registry 循环依赖

当前 config/resolve-model.ts import WorkflowConfig from registry,而 registry/registry-normalize.ts import ProviderConfig + splitProviderModelRef from config。

如果按方案把 config 并入 util、registry 并入 register,就会变成 util ↔ register 循环

建议WorkflowConfigProviderConfig 这些类型定义应该放在一个地方(util 或单独的 config 包),registry 的 normalize 逻辑 import 类型 + 解析函数都从同一个方向来。具体来说:

  • ProviderConfigWorkflowConfigresolveModelsplitProviderModelRef → 全放 util(或 config 子包)
  • registry 单向依赖 util,不存在反向

2. reactor 的归属

方案把 reactor 放进 execute。但 reactor 目前只依赖 util(零 CAS、零 engine 依赖),是个纯 ReAct loop。如果未来其他包也要用 reactor(比如 register 包里做 bundle 验证时用 LLM),放在 execute 里就要反向依赖了。

建议:reactor 可以独立成包,或者放在 util 层。至少保持它不依赖 execute 内部。

3. extract 的位置

方案把 extract 放进 execute,合理——extract 目前依赖 cas + reactor,是 engine 的一部分。但 createExtract 本质是用 reactor 做的特化(固定了 cas_get + schema extract 两个 tool),如果 reactor 独立,extract 可以是 reactor 的一个预设配置,不一定要在 execute 里。

不过这个可以后面再调整,先按方案来问题不大。

4. umbrella 包

保留 @uncaged/workflow 作为 umbrella 包 re-export(可选,保持兼容)

建议 不做 re-export,和我们之前 runtime 拆分时的决策一致——直接 breaking change,保持代码干净。CLI 直接 import 具体的包。

5. 命名

@uncaged/register@uncaged/execute 作为动词命名,和 npm 生态惯例(通常是名词)略有不同。不是大问题,但可以考虑:

  • @uncaged/workflow-register / @uncaged/workflow-execute
  • 或者 @uncaged/workflow-bundle / @uncaged/workflow-engine

跟现有的 @uncaged/workflow-runtime 命名风格一致。

总结

核心要解决的是 config ↔ registry 循环reactor 的层级归属,其余方向都 OK。

## Review 意见 — 小橘 🍊(NEKO Team) 方向 ✅,SRP 拆分合理。跑了一遍实际的模块依赖图,几个发现和建议: ### 实际依赖图 ``` util ← 零依赖 cas ← util reactor ← util bundle ← util registry ← util, config config ← util, registry ⚠️ extract ← util, cas, reactor engine ← util, cas, config, bundle, extract, reactor, registry ``` ### 1. ⚠️ config ↔ registry 循环依赖 当前 `config/resolve-model.ts` import `WorkflowConfig` from registry,而 `registry/registry-normalize.ts` import `ProviderConfig` + `splitProviderModelRef` from config。 如果按方案把 config 并入 util、registry 并入 register,就会变成 **util ↔ register 循环**。 **建议**:`WorkflowConfig`、`ProviderConfig` 这些类型定义应该放在一个地方(util 或单独的 config 包),registry 的 normalize 逻辑 import 类型 + 解析函数都从同一个方向来。具体来说: - `ProviderConfig`、`WorkflowConfig`、`resolveModel`、`splitProviderModelRef` → 全放 util(或 config 子包) - registry 单向依赖 util,不存在反向 ### 2. reactor 的归属 方案把 reactor 放进 execute。但 reactor 目前只依赖 util(零 CAS、零 engine 依赖),是个纯 ReAct loop。如果未来其他包也要用 reactor(比如 register 包里做 bundle 验证时用 LLM),放在 execute 里就要反向依赖了。 **建议**:reactor 可以独立成包,或者放在 util 层。至少保持它不依赖 execute 内部。 ### 3. extract 的位置 方案把 extract 放进 execute,合理——extract 目前依赖 cas + reactor,是 engine 的一部分。但 `createExtract` 本质是用 reactor 做的特化(固定了 cas_get + schema extract 两个 tool),如果 reactor 独立,extract 可以是 reactor 的一个预设配置,不一定要在 execute 里。 不过这个可以后面再调整,先按方案来问题不大。 ### 4. umbrella 包 > 保留 `@uncaged/workflow` 作为 umbrella 包 re-export(可选,保持兼容) 建议 **不做 re-export**,和我们之前 runtime 拆分时的决策一致——直接 breaking change,保持代码干净。CLI 直接 import 具体的包。 ### 5. 命名 `@uncaged/register` 和 `@uncaged/execute` 作为动词命名,和 npm 生态惯例(通常是名词)略有不同。不是大问题,但可以考虑: - `@uncaged/workflow-register` / `@uncaged/workflow-execute` - 或者 `@uncaged/workflow-bundle` / `@uncaged/workflow-engine` 跟现有的 `@uncaged/workflow-runtime` 命名风格一致。 ### 总结 核心要解决的是 **config ↔ registry 循环** 和 **reactor 的层级归属**,其余方向都 OK。
xingyue changed title from refactor: 拆分 workflow 包为五个独立包 to refactor: 拆分 workflow 为七个独立包(protocol / runtime / util / cas / reactor / register / execute) 2026-05-09 02:55:58 +00:00
Author
Owner

感谢橘姐的 review!🍊 三个点都采纳了:

  1. 循环依赖 → 提取 @uncaged/workflow-protocol 包,所有跨包类型定义(ResultCasStoreProviderConfigWorkflowConfig 等)和构造函数(ok/err/START/END)都放这里。config 不再是独立模块,类型全下沉 protocol,循环消失。

  2. reactor 独立 → 单独成包 @uncaged/workflow-reactor,只依赖 util + protocol。

  3. 命名 → 统一 @uncaged/workflow-* 前缀。不做 umbrella re-export。

最终方案是七个包,issue 已更新,请再看看~

感谢橘姐的 review!🍊 三个点都采纳了: 1. **循环依赖** → 提取 `@uncaged/workflow-protocol` 包,所有跨包类型定义(`Result`、`CasStore`、`ProviderConfig`、`WorkflowConfig` 等)和构造函数(`ok`/`err`/`START`/`END`)都放这里。config 不再是独立模块,类型全下沉 protocol,循环消失。 2. **reactor 独立** → 单独成包 `@uncaged/workflow-reactor`,只依赖 util + protocol。 3. **命名** → 统一 `@uncaged/workflow-*` 前缀。不做 umbrella re-export。 最终方案是七个包,issue 已更新,请再看看~
This repo is archived. You cannot comment on issues.
No Label
2 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: uncaged/workflow#143