重构: 后端编排拆解与DRY债收敛及命名纠偏

阶段1拆解: stream 系外移 stream_relay.rs,mod.rs 3048→2607,loop_body 502→83
技能收尾: regenerate/edit 回溯补技能,新增 read_skill 工具,项目级技能扫描
DRY: emit 双写 46 处收敛 event_bus 正典,KV 引号归一收口,LOCK-SLOW 33 处单行化
警示骨架 4→1 与压缩兜底 2→1,噪音目录档位收敛,truncate 同名陷阱消除
工具元数据落 ToolMeta 八维,7 张 match 表改查 registry,parity 测试锁等价
命名: is_noise_entry/teardown_round/probe_missed_terminal_event 等 6 项纠偏
This commit is contained in:
lxy
2026-10-01 19:35:19 +08:00
parent 3861e13b32
commit 75c5e23523
40 changed files with 2988 additions and 1964 deletions
+8 -22
View File
@@ -40,28 +40,13 @@ pub(crate) static BLACKLIST_BYPASS_TEST_LOCK: std::sync::Mutex<()> = std::sync::
/// 提取文件工具的路径参数(用于路径授权预校验)。
///
/// 仅对走 resolve_workspace_path 校验的文件工具返回路径;非文件工具返回空 Vec(不预校验)。
/// - 单路径工具(read_file/write_file/list_directory/patch_file/file_info/append_file/delete_file/search_files/grep)
/// 取 args["path"]
/// - rename_file 双路径取 args["from"] + args["to"](两个都需授权)
/// - run_command 不返回(它只走 validate_path 黑名单,不限定 workspace,High risk 靠人工审批)
/// 路径参数键查注册元数据(path_args 维度,DRY 债 #5 收敛):单路径工具(read_file/
/// write_file/list_directory/patch_file/file_info/append_file/delete_file/search_files/grep)
/// 声明 ["path"],rename_file 声明 ["from","to"](两个都需授权),其余工具默认空(不预校验)。
/// run_command 不声明(只走 validate_path 黑名单,不限定 workspace,High risk 靠人工审批)。
pub(crate) fn extract_file_tool_paths(tool_name: &str, args: &serde_json::Value) -> Vec<String> {
match tool_name {
"rename_file" => {
let mut v = Vec::new();
if let Some(from) = args.get("from").and_then(|x| x.as_str()) {
v.push(from.to_string());
}
if let Some(to) = args.get("to").and_then(|x| x.as_str()) {
v.push(to.to_string());
}
v
}
"read_file" | "write_file" | "list_directory" | "patch_file" | "file_info"
| "append_file" | "delete_file" | "search_files" | "grep" => {
args.get("path").and_then(|x| x.as_str()).map(|s| vec![s.to_string()]).unwrap_or_default()
}
_ => Vec::new(),
}
crate::commands::ai::tool_registry::ensure_tool_meta_seeded();
df_ai::ai_tools::extract_paths(df_ai::ai_tools::path_arg_keys(tool_name), args)
}
/// 路径授权预校验结果。
@@ -124,10 +109,11 @@ pub(crate) fn check_file_tool_auth(
}
if pending_dirs.is_empty() {
FileToolAuthOutcome::Authorized
} else if tool_name == "search_files" {
} else if df_ai::ai_tools::denies_unauthorized(tool_name) {
// 核心设计5:search_files 兜底 — 盲搜语义应拒不应询。
// search_files 仅在已授权目录可用;用户已通过 @项目 提供项目上下文,无需搜索文件系统。
// (黑名单已在上方 for 循环内短路返 Denied,走到此处均为 NeedsAuthorization 场景。)
// 拒绝名单查注册元数据(deny_unauthorized 维度,DRY 债 #5 收敛,现仅 search_files 声明);
// 其他文件工具保持原 NeedsAuth 弹窗逻辑完全不变。
FileToolAuthOutcome::Denied(
"search_files 仅在已授权目录可用;请用 @[项目] 引用或提供绝对路径,不要盲搜文件系统。".to_string(),