新增: AI Chat多项增强(审批去重/编辑重发/导出/实体引用/会话置顶搜索)+任务推进链df-nodes落地
This commit is contained in:
@@ -449,6 +449,30 @@
|
||||
- **边界**:取消分支在 B-07 + `set_cancelled` 补齐前恒 false(等价无取消,功能不残);跨工作流并发 HumanNode 在 B-06 修前有 Response 错配风险。
|
||||
- **状态**:📐 设计完成(2026-06-14),未实施。详见 [B-03-人工审批响应机制-2026-06-14.md](./B-03-人工审批响应机制-2026-06-14.md)。
|
||||
|
||||
## 任务推进链(7 态状态机 + 工作流联动)
|
||||
|
||||
> tasks 表从 todo→done 的状态推进链路。阶段1(7 态状态机 + advance_task CAS 原子写 + 软删除)已落地;阶段2(工作流联动:task_id + 完成回调 advance_task + DAG 模板)进行中。详细实施路径见 [任务推进链实施路径-2026-06-16.md](./任务推进链实施路径-2026-06-16.md) / [推进链阶段2实施路径-2026-06-16.md](./推进链阶段2实施路径-2026-06-16.md)。关联决策 D-260616-01~04(前端7态对齐 / 软删除 / Node trait 归属 / 阶段1先行)。
|
||||
|
||||
### advance_task / 状态机走 df-nodes Node trait,不复活 df-task(D-260616-03)
|
||||
- **决策**:任务推进业务逻辑(`can_transition_to` 状态机 / `advance_task` 原子写 / 闸门节点)落在 **df-nodes crate 的 Node trait 扩展**(`task_state_machine.rs` / `task_advance_node.rs`),IPC 层 thin 入口。不复活 2026-06-12 刚因零引用删除(cf017f8)的 df-task crate,不塞 commands/task.rs。
|
||||
- **原因/取舍**:① 对齐 D3「业务逻辑在 df-nodes 实现(Node trait 纯接口,df-workflow/src/node.rs:67)」原则;② 复活一个零引用刚删的 crate 是制造新死码,df-nodes 补 `df-storage` 依赖读 TaskRecord 即可(核实无循环依赖);③ IPC 层保持 thin(task.rs 仅 3 行转发)守住 D3 不让业务逻辑下沉 IPC。前端对齐后端 7 态(D-260616-01,types.rs:131,激活 InReview/Testing/Blocked 三闸门态)。
|
||||
- **状态**:✅ 阶段1 落地(commit d2cb38c:7态状态机 + advance_task CAS + 软删除,25 测试);🚧 阶段2 进行中(batch32:注册 TaskAdvanceNode + config 下沉 + HumanNode reject)。
|
||||
|
||||
### DagExecutor config 下沉:节点级覆盖全局级 deep_merge(④-1)
|
||||
- **决策**:`DagExecutor.run` 构造 `NodeContext.config` 从「`initial_config.clone()` 覆盖一切」改为「`deep_merge(node_def_config, initial_config)`」——节点级配置覆盖全局级(节点定义优先)。Dag 加 `node_configs: HashMap<NodeId, Value>`,build_dag 填入 NodeDef.config,run 合并下沉。
|
||||
- **原因/取舍**:原实现(executor.rs:99-107)用全局 initial_config 覆盖 NodeDef.config,**节点级配置被完全忽略**——TaskAdvanceNode.execute 读 `ctx.config.task_id` 拿到全局 config 而非节点定义写的 task_id,节点参数化失效。这是阶段2 的架构前置阻塞点:不修则 TaskAdvanceNode 无法从 DAG 接收 task_id。选「节点级覆盖全局级」(节点定义优先)而非全局覆盖节点级,因节点是更具体的配置源。deep_merge 对 Object 递归合并,非 Object 节点级直接覆盖。现有 HumanNode/AiNode 也受益(它们当前读 ctx.config 拿全局 config,但无人通过 NodeDef.config 定义节点参数故未暴露)。
|
||||
- **状态**:🚧 实施中(batch32 ④-1 agent:dag.rs + executor.rs + registry.rs + workflow.rs,配 deep_merge / node_config_overrides 测试)。
|
||||
|
||||
### DAG 模板硬编码,不建 workflow_defs 表(②-6)
|
||||
- **决策**:任务推进的工作流 DAG 模板(todo→in_progress / in_review→testing / testing→done 三条推进边 + 退回)**硬编码**在 `df-nodes/task_workflow_templates.rs`(导出 `template_for(target_status) -> DagDef`),**不建 workflow_defs 表**。`tasks.workflow_def_id` 字段留 None。
|
||||
- **原因/取舍**:模板数量少且稳定(3 条推进边 + 退回),建表需 CRUD UI + 版本管理 + 关联维护,过度工程。[业务系统设计-2026-06-12.md](./业务系统设计-2026-06-12.md) 确认 workflow_defs 从未建表(工作流定义 dag_json 内嵌 workflow_executions),延续此约定。硬编码模板随代码版本管理,零运行时配置开销。
|
||||
- **状态**:📐 设计定稿待实施(②-6,batch33+)。
|
||||
|
||||
### 工作流回调语义:成功与任务推进解耦,失败按 target 退回(②-3/②-4/②-5)
|
||||
- **决策**:工作流完成后回调 advance_task 的语义——**成功**(executor Ok):task_id + target_status 都 Some 时调 `advance_task_atomic`,回调失败只 warn 不回滚工作流(工作流已完成是事实,任务推进失败前端提示手动处理);**失败**(executor Err):按 target_status 推算退回态(testing→in_review / in_review→in_progress)调 advance,或加 `failure_target_status` 参数。HumanNode reject(②-5)从 Ok 改返 Err,使审查拒绝走 failed 触发退回。
|
||||
- **原因/取舍**:工作流成功与任务推进是两个独立事实,解耦避免「工作流成功但任务推进失败时回滚已完成工作流」的复杂性;失败退回让审查拒绝能回流上一态(review_rounds+1)。CAS 已防回调与手动 advance 并发撞(advance_task_atomic 捕获 InvalidState 降级)。跨表事务缺失(阶段2 回调失败降级,阶段3/4 补 Database.transaction())。
|
||||
- **状态**:📐 设计定稿待实施(batch32 做 ②-5 HumanNode reject 语义化,batch33 做 ②-3/②-4 回调)。
|
||||
|
||||
## 需求与待办
|
||||
|
||||
> 汇集散落于各决策条目状态(📐/🚧)的待办 + 新增需求细节 + 需求澄清。单一清单,避免遗漏。
|
||||
|
||||
93
docs/02-架构设计/推进链阶段2实施路径-2026-06-16.md
Normal file
93
docs/02-架构设计/推进链阶段2实施路径-2026-06-16.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# 推进链阶段2 实施路径(F-260616-06)
|
||||
|
||||
> 2026-06-16 Plan agent 评估产出。阶段1(7态状态机+advance_task CAS+软删除,commit d2cb38c)已落地。阶段2 目标:工作流联动任务推进(task_id + 完成回调 advance_task + DAG 模板)。
|
||||
>
|
||||
> 决策依据:D-260616-03(advance_task/节点走 df-nodes Node trait,不复活 df-task)。
|
||||
|
||||
## 一、现状基线(代码事实)
|
||||
|
||||
| 维度 | 现状 | 评估 |
|
||||
|---|---|---|
|
||||
| 推进链状态机 | `task_state_machine.rs` 7态 + can_transition/is_regression,完整单测 | ✅ 阶段2 复用零改动 |
|
||||
| advance_task 原子写 | `advance_task_atomic(repo,id,target)` IPC 直驱已注册,CAS+软删+退回 bump_rounds | ✅ 复用 |
|
||||
| TaskAdvanceNode (Node trait) | `task_advance_node.rs:101-166` 已实现,持 Arc<Database>,execute 读 ctx.config | ✅ 节点就绪,仅未注册 |
|
||||
| build_registry 未注册 | `state.rs:232` `fn build_registry()` 无参,无法构造持 db 的 TaskAdvanceNode | 🔴 阻塞点 |
|
||||
| run_workflow task_id | `workflow.rs:36` 签名无 task_id;但 WorkflowRecord.task_id 字段(models/migrations/crud)全链路就绪(写库硬编码 None) | 🟡 IPC 扩展,持久层零改动 |
|
||||
| DagExecutor.run | `executor.rs:49` initial_config.clone() 下沉 NodeContext.config,**忽略 NodeDef.config** | 🔴 DAG 设计缺口(④-1) |
|
||||
| WorkflowCompleted 事件 | 仅 total_duration_ms,无 execution_id/task_id | 🟡 回调需 IPC 闭包捕获 task_id |
|
||||
|
||||
## 二、实施步骤
|
||||
|
||||
### ④ 类 — 架构前置(阻塞)
|
||||
|
||||
**④-1 DagExecutor config 下沉语义修复**
|
||||
- 问题:`executor.rs:99-107` NodeContext.config = initial_config.clone() 覆盖 NodeDef.config,TaskAdvanceNode 读不到节点配置。
|
||||
- 修法(方案 A):`NodeContext.config = deep_merge(node_def_config, initial_config)` 节点级覆盖全局级。Dag 加 `node_configs: HashMap<NodeId, Value>`,build_dag 填入,run 合并下沉。
|
||||
- 文件锁:`crates/df-workflow/src/{dag.rs,executor.rs,registry.rs}` + `src-tauri/src/commands/workflow.rs`
|
||||
|
||||
### ② 类 — 需设计/行为变更(依赖④)
|
||||
|
||||
- **②-1 build_registry 注入 db + 注册 TaskAdvanceNode** — 改签名 `build_registry(db: Arc<Database>)` + move 闭包 `register("task_advance", move |_| Box::new(TaskAdvanceNode::new(db.clone())))` + init 调用传 db.clone()。不改 Node trait(构造时注入)。文件锁:`src-tauri/src/state.rs`
|
||||
- **②-2 run_workflow 加 task_id + target_status 参数** — IPC 签名扩展(Option 可选兼容)+ WorkflowRecord.task_id 填入 + spawn move 捕获。文件锁:`workflow.rs` + `api/workflow.ts` + `stores/project/workflow.ts`
|
||||
- **②-3 完成回调 WorkflowCompleted→advance_task** — spawn 闭包内 executor.run Ok 后,task_id+target_status 都 Some 时调 advance_task_atomic。失败 warn 不回滚(工作流成功语义与任务推进解耦)。文件锁:`workflow.rs`
|
||||
- **②-4 失败回调退回语义** — failed 时按 target_status 推算退回态(testing→in_review,in_review→in_progress)调 advance,或加 failure_target_status 参数。文件锁:`workflow.rs`
|
||||
- **②-5 HumanNode reject 语义化** — options 含 reject/block 时返 Err(非 Ok),使工作流 failed 触发退回。文件锁:`crates/df-nodes/src/human_node.rs`
|
||||
- **②-6 DAG 模板** — `df-nodes/task_workflow_templates.rs`(新)导出 `template_for(target_status)->DagDef`,5 前向边+退回。不建 workflow_defs 表(模板少且稳定,硬编码;tasks.workflow_def_id 留 None)。文件锁:`crates/df-nodes/src/task_workflow_templates.rs`
|
||||
|
||||
### ① 类 — 可并行(无依赖)
|
||||
|
||||
- **①-1 前端 TaskDetail 工作流推进按钮** — 与手动 advance 并存,调 workflowApi.run+监听进度。文件锁:`TaskDetail.vue` + `api/workflow.ts` + `stores/project/workflow.ts`
|
||||
- **①-3 i18n 文案** — `locales/{zh-CN,en}/tasks.ts`
|
||||
|
||||
## 三、风险 + 依赖
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|---|---|
|
||||
| 状态机联动一致性(工作流回调 vs 手动 advance 并发撞 CAS) | advance_task_atomic 已 CAS,回调层捕获 InvalidState 降级 |
|
||||
| advance 失败回滚(工作流 Ok 但回调 advance 失败) | 不回滚工作流(已完成事实),回调失败 warn+前端提示手动处理 |
|
||||
| 工作流 failed 退回语义 | ②-4 按 target 推算退回态或 failure_target_status 参数 |
|
||||
| DAG 循环 | DagExecutor 拓扑排序已检测环,充分 |
|
||||
| task_id 缺失降级 | task_id/target_status 都 None 时不触发回调,向后兼容 |
|
||||
| DagExecutor config 下沉(④-1) | 必须先修,否则节点参数化失效 |
|
||||
| HumanNode reject 语义化(②-5) | 阶段2 必做,否则审查拒绝无法退回 |
|
||||
| 跨表事务缺失 | 阶段2 回调失败降级,阶段3/4 补 Database.transaction() |
|
||||
|
||||
## 四、实施顺序(串行关键路径)
|
||||
|
||||
```
|
||||
④-1 (config 下沉)
|
||||
→ ②-1 (注册 TaskAdvanceNode) ← 单 task_advance 节点 DAG 可端到端
|
||||
→ ②-5 (HumanNode reject 语义化) ← 审查拒绝能走 failed
|
||||
→ ②-2 (run_workflow task_id)
|
||||
→ ②-3 (完成回调) ← AiNode+HumanNode 工作流推进任务可跑
|
||||
→ ②-4 (失败回调退回)
|
||||
→ ②-6 (DAG 模板) ← 前端可一键触发
|
||||
→ ①-1 / ①-3 (前端接入 + i18n) ← 并行收尾
|
||||
```
|
||||
|
||||
**最小可验证里程碑**(④-1+②-1+②-2+②-3):`run_workflow(name, dag, {}, taskId="t1", targetStatus="in_progress")`,DAG=单 task_advance 节点,验证任务 todo→in_progress。无 AiNode/HumanNode 依赖,纯推进链联动验证。
|
||||
|
||||
## 五、TaskAdvanceNode 注册路径
|
||||
|
||||
```rust
|
||||
fn build_registry(db: Arc<Database>) -> NodeRegistry {
|
||||
let mut registry = NodeRegistry::new();
|
||||
registry.register("human", |_| Box::new(df_nodes::human_node::HumanNode));
|
||||
registry.register("ai", |_| Box::new(df_nodes::ai_node::AiNode));
|
||||
registry.register("task_advance", move |_| {
|
||||
Box::new(df_nodes::task_advance_node::TaskAdvanceNode::new(db.clone()))
|
||||
});
|
||||
registry
|
||||
}
|
||||
```
|
||||
|
||||
工厂闭包 move 捕获 db(构造时注入),每次 create 调用 clone 构造新实例。不改 Node trait。
|
||||
|
||||
## 六、DAG 模板形态(阶段2)
|
||||
|
||||
工作流级 target_status(一个工作流对应一次推进):
|
||||
- `todo→in_progress`:单 AiNode 执行
|
||||
- `in_review→testing`:AiNode 自审 + HumanNode 核对(reject→②-5 Err→failed→②-4 退回 in_progress,review_rounds+1)
|
||||
- `testing→done`:HumanNode 最终核对
|
||||
|
||||
节点级不携带 target_status(避免节点间状态不一致),工作流级统一。
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
### 知识删除语义:knowledge_archive 软删除(命名统一)[2026-06-13]
|
||||
|
||||
- **决策**:知识删除 command 命名 `knowledge_archive`(执行 `UPDATE status='archived'`),**不叫 knowledge_delete**。匹配 `ai_conversation_archive` 先例;主列表 `knowledge_list(status=None)` 默认 `AND status!='archived'` 过滤。
|
||||
- **决策**:知识删除 command 命名 `knowledge_archive`(执行 `UPDATE status='archived'`),**不叫 knowledge_delete**。匹配 `ai_conversation_archive` 先例;主列表 `knowledge_list(status=None)` 默认仅返回 published(library 纯已发布,[2026-06-16] F-260616-02 决策 a 收窄:pending_review 归 `knowledge_list_candidates` 收件箱,不再混杂 library)。
|
||||
- **原因/取舍**:idea/task/project 的 `delete_xxx` 都是硬删(DELETE FROM),若 knowledge 也叫 delete 却做归档,API 语义混淆(调用方期望数据消失,实际还在 DB)。conversation 模块已有正确先例(archive 命名表示软删除)。软删除复用 archived 状态,数据保留可追溯,列表默认过滤保证用户感知「已删除」。状态机 published→archived 也走同一路径。
|
||||
- **状态**:✅ 已实施(Tier 1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user