From 840949ad05868071935bee94b3e9e9e5c2480ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Wed, 1 Jul 2026 23:37:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=AE=A1=E6=9F=A5=E5=8F=91=E7=8E=B0=E7=9A=84=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E4=B8=8E=E5=85=BC=E5=AE=B9=E6=80=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - git_worktree: commit config 改用 --local 避免污染全局 git config - git_worktree: merge-tree 改用旧版兼容语法(三参数替代 --write-tree) - coordinator: executor 'static 约束加注释说明(JoinSet spawn 要求) - coordinator: Token reserve 按层 SubTask 数累加(原固定 10k 不准确) - coordinator: 更新结构体注释(反映当前并行实现而非 Phase 1 串行) - 39 个测试全绿,行为零回归 --- crates/df-ai/src/coordinator.rs | 22 ++++++++++++---------- crates/df-ai/src/git_worktree.rs | 30 +++++++++++++++--------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/crates/df-ai/src/coordinator.rs b/crates/df-ai/src/coordinator.rs index 1fb6fc5..ebb4273 100644 --- a/crates/df-ai/src/coordinator.rs +++ b/crates/df-ai/src/coordinator.rs @@ -129,16 +129,15 @@ pub struct ConflictItem { /// 多 Agent 协作调度器 /// -/// # Phase 1(当前) +/// 当前实现: +/// - 规则驱动 decompose(关键词匹配) +/// - dispatch_with_budget: JoinSet 层内并行 + token 预算管控 +/// - dispatch_serial: 串行降级路径(无 'static 约束) +/// - merge: 拼接产出 + 同文件冲突检测 /// -/// 规则驱动 decompose + 串行 dispatch + 简单拼接 merge。 -/// 适用于「读后写」「搜索后分析」等可预测的意图组合。 -/// -/// # Phase 2(预留) -/// -/// - LLM 驱动 decompose(LLM 生成 Plan 结构) -/// - JoinSet 并行 dispatch(层内并行) -/// - Reviewer Agent 仲裁 merge(冲突检测 + 自动解决) +/// Phase 2 预留: +/// - LLM 驱动 decompose +/// - Reviewer Agent 仲裁 pub struct Coordinator { /// 人设注册表(内置 5 人设 + 自定义) registry: PersonaRegistry, @@ -268,6 +267,9 @@ impl Coordinator { budget: Option<&Arc>, ) -> Vec where + // 'static + Clone 要求:JoinSet::spawn 需要 owned 闭包(不能借用 self/db)。 + // 调用方需用 Arc 包裹共享状态(db/session)传入闭包。 + // 不需要并行时用 dispatch_serial(无 'static 约束)。 F: Fn(SubTask, String) -> Fut + Clone + Send + Sync + 'static, Fut: std::future::Future + Send, { @@ -308,7 +310,7 @@ impl Coordinator { } let can_parallel = budget - .map(|b| b.try_reserve(10_000)) + .map(|b| b.try_reserve(layer.len() as u64 * 10_000)) // 每层按 SubTask 数累加 .unwrap_or(true); if can_parallel { diff --git a/crates/df-ai/src/git_worktree.rs b/crates/df-ai/src/git_worktree.rs index b4212e1..657bc86 100644 --- a/crates/df-ai/src/git_worktree.rs +++ b/crates/df-ai/src/git_worktree.rs @@ -129,14 +129,14 @@ pub fn commit_worktree(wt_path: &Path, message: &str) -> Result<(), WorktreeErro // commit 失败可能因无 user.email 配置(测试环境),尝试自动配 let stderr = String::from_utf8_lossy(&commit.stderr); if stderr.contains("user.email") || stderr.contains("user.name") { - // 降级:设置临时配置后重试 + // 降级:设置 worktree 局部配置(--local 不污染全局 git config)后重试 Command::new("git") - .args(["config", "user.email", "devflow@ai.local"]) + .args(["config", "--local", "user.email", "devflow@ai.local"]) .current_dir(wt_path) .output() .ok(); Command::new("git") - .args(["config", "user.name", "DevFlow Agent"]) + .args(["config", "--local", "user.name", "DevFlow Agent"]) .current_dir(wt_path) .output() .ok(); @@ -167,23 +167,23 @@ pub fn merge_branch( plan_wt_path: &Path, subtask_branch: &str, ) -> Result { - // 先用 merge-tree 预检 + // 用旧版兼容的 merge-tree(base branch → 输出冲突树) + // --write-tree 需 Git 2.38+,改用三参数 merge-tree + // 成功(exit 0)= 无冲突可自动合并;非0且有输出 = 冲突 + let base = "HEAD"; let precheck = Command::new("git") - .args(["merge-tree", "--write-tree", "--messages", "HEAD", subtask_branch]) + .args(["merge-tree", base, subtask_branch, base]) .current_dir(plan_wt_path) .output() .map_err(|e| WorktreeError::GitFailed(format!("git merge-tree 失败: {}", e)))?; - // merge-tree --write-tree 成功(exit 0)= 无冲突可自动合并; - // 非0(冲突)且 stdout 非空 = 有冲突 - if !precheck.status.success() { - let stdout = String::from_utf8_lossy(&precheck.stdout); - if !stdout.is_empty() { - return Ok(MergeResult::Conflict { - branch: subtask_branch.to_string(), - details: stdout.to_string(), - }); - } + // merge-tree 输出含 conflict marker(<<<<<<<)时表示有冲突 + let precheck_stdout = String::from_utf8_lossy(&precheck.stdout); + if precheck_stdout.contains("<<<<<<<") || precheck_stdout.contains("=======") { + return Ok(MergeResult::Conflict { + branch: subtask_branch.to_string(), + details: precheck_stdout.to_string(), + }); } // 无冲突,执行实际 merge