新增: 批次工作落地(推进链/评估闭环/事件总线/并发/加固) + 技术债清理 + 文档整理
后端: - 工作流推进链(D-03):advance_task/状态机/闸门走 df-nodes Node trait,conditions 条件引擎扩展 - 想法评估闭环:启发式评分+对抗评估,df-ideas/scoring + df-storage/idea_eval_repo + idea 前端打通 - 全局事件数据总线:df-ai/context+context_helpers+augmentation 跨模块解耦 - AI planner/plan_hint/intent:aichat B 路线并行多轮基础 - patch_file 加固(TD-03/04):读改写整体锁防 lost update,expected_hash 合约闭环 - 压缩超时兜底(F-15 卡死根治) - F-09 多会话并发:LlmConcurrency per-conv + streamingGuard 前端守护 + verify 脚本 - 知识注入 DRY/skills/audit 扩展 清理: - aichat 技术债(误报 allow/死导入/过时注释 30 项) - URGENT.md 删除(11 项加急全解决/迁 todo) - 文档整理(todo/待决策/待审查/ARCHITECTURE/INDEX + 总线/技术债审查新文档)
This commit is contained in:
@@ -5,6 +5,7 @@ use std::collections::HashMap;
|
||||
use df_types::events::WorkflowEvent;
|
||||
use df_types::types::NodeId;
|
||||
|
||||
use crate::conditions::ConditionEngine;
|
||||
use crate::dag::Dag;
|
||||
use crate::eventbus::EventBus;
|
||||
use crate::node::{NodeContext, NodeOutput};
|
||||
@@ -57,14 +58,16 @@ impl DagExecutor {
|
||||
|
||||
tracing::info!("DAG 执行开始,共 {} 层", layers.len());
|
||||
|
||||
// 预建入边索引:target → 直接前驱列表(O(E) 一次构建)
|
||||
// 预建入边索引:target → 直接前驱列表 + 边条件表达式(O(E) 一次构建)
|
||||
// 避免在内层按节点循环中调用 dag.predecessors()(每次 O(E) 全表扫描,整体 O(V·E))。
|
||||
let mut adjacency_in: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
||||
// 含 condition 是为 conditions-eval feature 接入:flag 开时按入边 condition 过滤前驱 input。
|
||||
// flag 关时 condition 字段被忽略,行为与增强前完全一致(零破坏)。
|
||||
let mut adjacency_in: HashMap<NodeId, Vec<(NodeId, Option<String>)>> = HashMap::new();
|
||||
for edge in &dag.edges {
|
||||
adjacency_in
|
||||
.entry(edge.target.clone())
|
||||
.or_default()
|
||||
.push(edge.source.clone());
|
||||
.push((edge.source.clone(), edge.condition.clone()));
|
||||
}
|
||||
|
||||
for (layer_idx, layer) in layers.iter().enumerate() {
|
||||
@@ -77,6 +80,61 @@ impl DagExecutor {
|
||||
anyhow::anyhow!("节点 {} 不存在于 DAG 中", node_id)
|
||||
})?;
|
||||
|
||||
// 构建节点上下文:通过入边索引 O(入度) 取前驱,而非 O(E) 全表扫描。
|
||||
//
|
||||
// conditions-eval feature(默认关):
|
||||
// 关:所有入边 inputs 全收集,condition 字段完全忽略 = 旧行为(零破坏)。
|
||||
// 开:对带 condition 的入边以 source output.data 为 context 求值;
|
||||
// false 则不收集该前驱 input。若节点【存在带 condition 的入边,且无任何
|
||||
// 入边(条件或无条件)放行】,则跳过该节点执行(不入 outputs、保持 Pending、
|
||||
// 不 emit),实现条件路由。无条件边 source 有 output 即视为放行。
|
||||
// 求值失败保守 false(对齐引擎语义)。
|
||||
//
|
||||
// 注:跳过判定在 set_running 之前 —— 跳过的节点不应被标记 Running/触发事件,
|
||||
// 保持 Pending 终态(与"条件未命中"语义一致)。
|
||||
let eval_conditions = cfg!(feature = "conditions-eval");
|
||||
let mut inputs: HashMap<NodeId, NodeOutput> = HashMap::new();
|
||||
let mut has_any_cond_edge = false;
|
||||
let mut any_edge_passed = false; // 任一入边放行(含无条件边)
|
||||
if let Some(preds) = adjacency_in.get(node_id) {
|
||||
for (pred_id, cond) in preds {
|
||||
if let Some(out) = outputs.get(pred_id) {
|
||||
if eval_conditions {
|
||||
if let Some(cond) = cond {
|
||||
has_any_cond_edge = true;
|
||||
// 以 source output.data 为 context 求值;失败保守 false
|
||||
let passed = ConditionEngine::evaluate(cond, &out.data)
|
||||
.unwrap_or(false);
|
||||
if passed {
|
||||
inputs.insert(pred_id.clone(), out.clone());
|
||||
any_edge_passed = true;
|
||||
}
|
||||
} else {
|
||||
// 无 condition 的入边:无条件放行(必收集)
|
||||
inputs.insert(pred_id.clone(), out.clone());
|
||||
any_edge_passed = true;
|
||||
}
|
||||
} else {
|
||||
// flag 关:condition 完全忽略,旧行为全收集
|
||||
inputs.insert(pred_id.clone(), out.clone());
|
||||
any_edge_passed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 根节点(无入边):不参与条件跳过判定,正常执行
|
||||
any_edge_passed = true;
|
||||
}
|
||||
|
||||
// 条件路由:flag 开 + 存在条件边 + 没有任何入边放行 → 跳过执行
|
||||
if eval_conditions && has_any_cond_edge && !any_edge_passed {
|
||||
tracing::info!(
|
||||
"节点 {} 所有入边条件均不满足,跳过执行(条件路由)",
|
||||
node_id
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 发送 NodeStarted 事件
|
||||
self.event_bus
|
||||
.send(WorkflowEvent::NodeStarted {
|
||||
@@ -86,16 +144,6 @@ impl DagExecutor {
|
||||
|
||||
self.state_machine.set_running(node_id.clone())?;
|
||||
|
||||
// 构建节点上下文:通过入边索引 O(入度) 取前驱,而非 O(E) 全表扫描
|
||||
let mut inputs = HashMap::new();
|
||||
if let Some(preds) = adjacency_in.get(node_id) {
|
||||
for pred_id in preds {
|
||||
if let Some(out) = outputs.get(pred_id) {
|
||||
inputs.insert(pred_id.clone(), out.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ctx = NodeContext {
|
||||
node_id: node_id.clone(),
|
||||
inputs,
|
||||
|
||||
Reference in New Issue
Block a user