新增: AST 代码智能 read_symbol 三态(治 prompt 爆,信息密度驱动)
tree-sitter 语法层符号解析,治 aichat read_file 全文回灌 prompt 爆(e46f5605 360K/8dfe0b94 5M)。 核心思想:信息密度≠压缩,read_symbol 按语义层级返符号骨架/全文,非物理读全文件。 - code_intel.rs: grammar_for 集中 lookup(Rust/TS/JS/Vue借TS,3 grammar 4 类)+ read_symbol 三态(骨架默认/全文)+ 不报错兜底(无grammar/解析失败/未找到→grep提示) - tool_registry 注册 read_symbol(对齐 read_file handler 闭包模式) - Cargo.toml 加 tree-sitter 0.25 + rust/typescript/javascript grammar - AST 设计文档 grammar 策略章节定稿(静态编译+lookup,不动态不trait) 实测: code_intel.rs 全文 21851B vs read_symbol 骨架 897B,降 24.4x(达设计目标一个量级+)。单测 14 全过。
This commit is contained in:
@@ -1042,6 +1042,50 @@ fn register_file_tools(
|
||||
})
|
||||
})},
|
||||
);
|
||||
registry.register(
|
||||
"read_symbol", "AST 符号解析(信息密度驱动,治 read_file 全文回灌 prompt 爆)。提取函数/结构体/类等符号:默认返回骨架(签名+行范围+内部调用,极小高密度);传 full=true 取完整定义体。不支持/未找到时回退提示用 grep+read_file。Phase1 支持 .rs/.ts/.tsx/.js/.jsx/.vue。",
|
||||
df_ai::ai_tools::object_schema(vec![("path", "string", true), ("symbol", "string", true), ("full", "boolean", false), ("kind", "string", 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!("路径含非法字符"))?;
|
||||
let symbol = args["symbol"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 symbol 参数"))?;
|
||||
let full = args["full"].as_bool().unwrap_or(false);
|
||||
let kind_hint = args["kind"].as_str();
|
||||
use tokio::fs::File;
|
||||
use tokio::io::AsyncReadExt;
|
||||
let mut file = File::open(path).await
|
||||
.map_err(|e| anyhow::anyhow!("无法访问文件 {}: {}", path, e))?;
|
||||
let metadata = file.metadata().await
|
||||
.map_err(|e| anyhow::anyhow!("读取元数据失败 {}: {}", path, e))?;
|
||||
if metadata.len() > 1_048_576 {
|
||||
anyhow::bail!("文件超过 1MB 限制 ({} 字节)", metadata.len());
|
||||
}
|
||||
let file_hash = compute_file_hash(&metadata);
|
||||
let mut content = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut content).await {
|
||||
if e.kind() == std::io::ErrorKind::InvalidData {
|
||||
return Ok(serde_json::json!({
|
||||
"path": path, "binary": true, "size": metadata.len(), "file_hash": file_hash,
|
||||
"fallback": true, "reason": "binary",
|
||||
"suggestion": "文件非 UTF-8 文本,无法 AST 解析,用 grep 搜内容",
|
||||
}));
|
||||
}
|
||||
anyhow::bail!("读取文件失败: {}", e);
|
||||
}
|
||||
// 调 code_intel 纯函数(三态 + 兜底,不 panic)
|
||||
Ok(crate::commands::ai::code_intel::read_symbol(
|
||||
&content, &file_hash, path, symbol, full, kind_hint,
|
||||
))
|
||||
})
|
||||
})},
|
||||
);
|
||||
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)]),
|
||||
|
||||
Reference in New Issue
Block a user