added ast-grep use

g3 tool use of ast-grep command with batching for faster code exploration.
This commit is contained in:
Jochen
2025-11-01 14:59:55 +11:00
parent f89bbfc89a
commit ad9ba5e5d8
4 changed files with 919 additions and 1 deletions

View File

@@ -2,6 +2,7 @@ pub mod error_handling;
pub mod project;
pub mod task_result;
pub mod ui_writer;
pub mod code_search;
pub use task_result::TaskResult;
#[cfg(test)]
@@ -1184,10 +1185,26 @@ The tool will execute immediately and you'll receive the result (success or erro
# Instructions
1. Analyze the request and break down into smaller tasks if appropriate
2. Execute ONE tool at a time
2. Execute ONE tool at a time. An exception exists for when you're writing files. See below.
3. STOP when the original request was satisfied
4. Call the final_output tool when done
Exception to using ONE tool at a time:
If all youre doing is WRITING files, and you dont need to do anything else between each step.
You can issue MULTIPLE write_file tool calls in a request, however you may ONLY make a SINGLE write_file call for any file in that request.
For example you may call:
[START OF REQUEST]
write_file(\"helper.rs\", \"...\")
write_file(\"file2.txt\", \"...\")
[DONE]
But NOT:
[START OF REQUEST]
write_file(\"helper.rs\", \"...\")
write_file(\"file2.txt\", \"...\")
write_file(\"helper.rs\", \"...\")
[DONE]
# Task Management
Use todo_read and todo_write for tasks with 3+ steps, multiple files/components, or uncertain scope.
@@ -1860,6 +1877,64 @@ Template:
}),
},
];
// Add code_search tool
tools.push(Tool {
name: "code_search".to_string(),
description: "Batch syntax-aware searches via ast-grep. Supports up to 20 pattern or YAML-rule searches in parallel; returns JSON matches (stream-collated).".to_string(),
input_schema: json!({
"type": "object",
"properties": {
"searches": {
"type": "array",
"maxItems": 20,
"items": {
"type": "object",
"properties": {
"name": { "type": "string", "description": "Label for this search." },
"mode": {
"type": "string",
"enum": ["pattern", "yaml"],
"description": "`pattern` uses `ast-grep run`; `yaml` uses `ast-grep scan --inline-rules`."
},
// pattern mode (fast one-off)
"pattern": { "type": "string", "description": "ast-grep pattern code (e.g., \"async fn $NAME($$$ARGS) { $$$ }\")"},
"language": { "type": "string", "description": "Optional language for pattern mode; ast-grep may infer from file extensions if omitted." },
// yaml mode (full rule object)
"rule_yaml": { "type": "string", "description": "A full YAML rule object text. Must include `id`, `language`, and `rule`." },
// targeting
"paths": { "type": "array", "items": { "type": "string" }, "description": "Paths/dirs to search. Defaults to current dir if empty." },
"globs": { "type": "array", "items": { "type": "string" }, "description": "Optional include/exclude globs for CLI --globs." },
// result formatting & performance knobs
"json_style": { "type": "string", "enum": ["pretty","stream","compact"], "default": "stream", "description": "Use stream for large codebases." },
"context": { "type": "integer", "minimum": 0, "maximum": 20, "default": 0, "description": "CLI -C context lines in text output; also affects JSON `lines` field." },
"threads": { "type": "integer", "minimum": 1, "description": "Optional override for ast-grep -j (per process)." },
"include_metadata": { "type": "boolean", "default": false, "description": "If yaml mode and rule has metadata, add --include-metadata." },
// robustness
"no_ignore": {
"type": "array",
"items": { "type": "string", "enum": ["hidden","dot","exclude","global","parent","vcs"] },
"description": "Forwarded to --no-ignore to bypass ignore files/hidden."
},
// severity overrides for yaml mode
"severity": {
"type": "object",
"additionalProperties": { "type": "string", "enum": ["error","warning","info","hint","off"] },
"description": "Optional map<ruleId, severity> -> passed via --error/--warning/--info/--hint/--off."
},
// per-search timeout seconds (default 60)
"timeout_secs": { "type": "integer", "minimum": 1, "default": 60 }
},
"required": ["name","mode"]
}
},
// global concurrency & truncation
"max_concurrency": { "type": "integer", "minimum": 1, "default": 4 },
"max_matches_per_search": { "type": "integer", "minimum": 1, "default": 500 }
},
"required": ["searches"]
}),
});
// Add WebDriver tools if enabled
if enable_webdriver {
@@ -4437,6 +4512,41 @@ Template:
Ok("❌ Computer control not enabled. Set computer_control.enabled = true in config.".to_string())
}
}
"code_search" => {
debug!("Processing code_search tool call");
// Parse the request
let request: crate::code_search::CodeSearchRequest = match serde_json::from_value(tool_call.args.clone()) {
Ok(req) => req,
Err(e) => {
return Ok(format!("❌ Invalid code_search arguments: {}", e));
}
};
// Execute the code search
match crate::code_search::execute_code_search(request).await {
Ok(response) => {
// Serialize the response to JSON
match serde_json::to_string_pretty(&response) {
Ok(json_output) => {
Ok(format!("✅ Code search completed\n{}", json_output))
}
Err(e) => {
Ok(format!("❌ Failed to serialize response: {}", e))
}
}
}
Err(e) => {
// Check if it's an ast-grep not found error and provide helpful message
let error_msg = e.to_string();
if error_msg.contains("ast-grep not found") {
Ok(format!("{}", error_msg))
} else {
Ok(format!("❌ Code search failed: {}", error_msg))
}
}
}
}
_ => {
warn!("Unknown tool: {}", tool_call.tool);
Ok(format!("❓ Unknown tool: {}", tool_call.tool))