新增: Phase 4 注入 — @[项目] 关联任务/灵感 + 三个工具 path 可选
- Augmentation 新增 extra 字段(项目关联信息/任务关联信息/灵感关联信息) - ProjectResolver: @[项目] 时自动查前5条进行中任务+前3条待评估灵感 - TaskResolver/IdeaResolver: extra 预留(后续按需追加) - render_one 渲染 extra 行 - search_files/grep/list_directory path 改为可选,不传时返回引导提示
This commit is contained in:
@@ -1549,18 +1549,19 @@ fn register_file_tools(
|
||||
})},
|
||||
);
|
||||
registry.register(
|
||||
"list_directory", "列出目录内容,返回文件和子目录列表(名称、类型、大小)",
|
||||
df_ai::ai_tools::object_schema(vec![("path", "string", true), ("recursive", "boolean", false), ("skip_noise_dirs", "boolean", false), ("max_depth", "integer", false)]),
|
||||
RiskLevel::Low,
|
||||
{ let allowed_dirs = allowed_dirs.clone(); Box::new(move |args: serde_json::Value| {
|
||||
let allowed_dirs = allowed_dirs.clone();
|
||||
Box::pin(async move {
|
||||
let snap = allowed_dirs.read().await.clone();
|
||||
let resolved = resolve_workspace_path_with_allowed(
|
||||
args["path"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 path 参数"))?,
|
||||
&snap,
|
||||
)?;
|
||||
let path = resolved.to_str().ok_or_else(|| anyhow::anyhow!("路径含非法字符"))?;
|
||||
"list_directory", "列出目录内容,返回文件和子目录列表(名称、类型、大小)。path 可选,不传时返回引导提示",
|
||||
df_ai::ai_tools::object_schema(vec![("path", "string", false), ("recursive", "boolean", false), ("skip_noise_dirs", "boolean", false), ("max_depth", "integer", false)]),
|
||||
RiskLevel::Low,
|
||||
{ let allowed_dirs = allowed_dirs.clone(); Box::new(move |args: serde_json::Value| {
|
||||
let allowed_dirs = allowed_dirs.clone();
|
||||
Box::pin(async move {
|
||||
let p = args["path"].as_str().unwrap_or("");
|
||||
if p.is_empty() {
|
||||
return Ok(serde_json::json!({"error": "请指定搜索目录。可用 @[项目名] 引用已绑定的项目目录,或直接提供绝对路径。"}));
|
||||
}
|
||||
let snap = allowed_dirs.read().await.clone();
|
||||
let resolved = resolve_workspace_path_with_allowed(p, &snap)?;
|
||||
let path = resolved.to_str().ok_or_else(|| anyhow::anyhow!("路径含非法字符"))?;
|
||||
let recursive = args["recursive"].as_bool().unwrap_or(false);
|
||||
let skip_noise = args["skip_noise_dirs"].as_bool().unwrap_or(true);
|
||||
// BUG-260617-09: max_depth 由 LLM 参数控制,无上限时虽 entries 上限(1000)
|
||||
@@ -2128,7 +2129,7 @@ fn register_file_tools(
|
||||
let grep_schema = {
|
||||
let mut props = serde_json::Map::new();
|
||||
props.insert("pattern".into(), serde_json::json!({ "type": "string", "description": "正则表达式(默认大小写敏感)。无特殊字符时等价字面包含匹配。必填" }));
|
||||
props.insert("path".into(), serde_json::json!({ "type": "string", "description": "搜索根目录(锚 workspace + path_auth 授权)。必填" }));
|
||||
props.insert("path".into(), serde_json::json!({ "type": "string", "description": "搜索根目录(锚 workspace + path_auth 授权)。不传时引导用户指定" }));
|
||||
props.insert("glob".into(), serde_json::json!({ "type": "string", "description": "可选文件名 glob 过滤(如 *.rs / *.ts),单段匹配;不传搜全部文件" }));
|
||||
props.insert("output_mode".into(), serde_json::json!({ "type": "string", "description": "输出模式:content(默认,行级匹配+上下文)/ files_with_matches(仅命中文件名)/ count(每文件命中行数)", "enum": ["content", "files_with_matches", "count"] }));
|
||||
props.insert("-n".into(), serde_json::json!({ "type": "boolean", "description": "content 模式是否含行号(默认 true)" }));
|
||||
@@ -2138,21 +2139,22 @@ fn register_file_tools(
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": props,
|
||||
"required": ["pattern", "path"],
|
||||
"required": ["pattern"],
|
||||
})
|
||||
};
|
||||
registry.register(
|
||||
"grep", "跨文件内容搜索(grep -rn 模式)。参数:pattern(正则,大小写敏感,无特殊字符时等价字面包含)、path(搜索根,文件或目录均可——传单文件仅搜该文件,锚 workspace + path_auth 授权)、glob(可选文件名过滤如 *.rs)、output_mode(content/files_with_matches/count)、-n(行号默认 true)、-i(大小写不敏感默认 false)、-C(上下文行数默认 0)、max_results(上限默认 50)。跳过噪音目录/噪音文件/symlink/二进制文件。返回 matches(files_with_matches 模式)或 matches(含 file/line/content/context,content 模式)+ total + truncated。授权目录内放行,未授权触发目录授权申请(AiDirAuthRequired)",
|
||||
"grep", "跨文件内容搜索(grep -rn 模式)。参数:pattern(正则,大小写敏感,无特殊字符时等价字面包含)、path(搜索根,可选,不传时返回引导提示)、glob(可选文件名过滤如 *.rs)、output_mode(content/files_with_matches/count)、-n(行号默认 true)、-i(大小写不敏感默认 false)、-C(上下文行数默认 0)、max_results(上限默认 50)。跳过噪音目录/噪音文件/symlink/二进制文件。返回 matches(files_with_matches 模式)或 matches(含 file/line/content/context,content 模式)+ total + truncated。授权目录内放行,未授权触发目录授权申请(AiDirAuthRequired)",
|
||||
grep_schema,
|
||||
RiskLevel::Low,
|
||||
{ let allowed_dirs = allowed_dirs.clone(); Box::new(move |args: serde_json::Value| {
|
||||
let allowed_dirs = allowed_dirs.clone();
|
||||
Box::pin(async move {
|
||||
let p = args["path"].as_str().unwrap_or("");
|
||||
if p.is_empty() {
|
||||
return Ok(serde_json::json!({"error": "请指定搜索目录。可用 @[项目名] 引用已绑定的项目目录,或直接提供绝对路径。"}));
|
||||
}
|
||||
let snap = allowed_dirs.read().await.clone();
|
||||
let resolved = resolve_workspace_path_with_allowed(
|
||||
args["path"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 path 参数"))?,
|
||||
&snap,
|
||||
)?;
|
||||
let resolved = resolve_workspace_path_with_allowed(p, &snap)?;
|
||||
let root = resolved.to_str().ok_or_else(|| anyhow::anyhow!("路径含非法字符"))?;
|
||||
let pattern = args["pattern"].as_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("缺少 pattern 参数"))?;
|
||||
@@ -2273,16 +2275,17 @@ fn register_file_tools(
|
||||
// ── 文件搜索 (Low risk) ──
|
||||
registry.register(
|
||||
"search_files", "在指定目录下搜索匹配模式(字符串包含匹配)的文件名,支持 offset/limit 分页。返回 results、total、has_more。默认 limit=50",
|
||||
df_ai::ai_tools::object_schema(vec![("path", "string", true), ("pattern", "string", true), ("recursive", "boolean", false), ("offset", "integer", false), ("limit", "integer", false)]),
|
||||
df_ai::ai_tools::object_schema(vec![("path", "string", false), ("pattern", "string", true), ("recursive", "boolean", false), ("offset", "integer", false), ("limit", "integer", false)]),
|
||||
RiskLevel::Low,
|
||||
{ let allowed_dirs = allowed_dirs.clone(); Box::new(move |args: serde_json::Value| {
|
||||
let allowed_dirs = allowed_dirs.clone();
|
||||
Box::pin(async move {
|
||||
let p = args["path"].as_str().unwrap_or("");
|
||||
if p.is_empty() {
|
||||
return Ok(serde_json::json!({"error": "请指定搜索目录。可用 @[项目名] 引用已绑定的项目目录,或直接提供绝对路径。"}));
|
||||
}
|
||||
let snap = allowed_dirs.read().await.clone();
|
||||
let resolved = resolve_workspace_path_with_allowed(
|
||||
args["path"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 path 参数"))?,
|
||||
&snap,
|
||||
)?;
|
||||
let resolved = resolve_workspace_path_with_allowed(p, &snap)?;
|
||||
let path = resolved.to_str().ok_or_else(|| anyhow::anyhow!("路径含非法字符"))?;
|
||||
let pattern = args["pattern"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 pattern 参数"))?;
|
||||
let recursive = args["recursive"].as_bool().unwrap_or(false);
|
||||
|
||||
Reference in New Issue
Block a user