Skip to main content

steer_core/tools/static_tools/
astgrep.rs

1use async_trait::async_trait;
2
3use super::workspace_op_error;
4use crate::tools::capability::Capabilities;
5use crate::tools::static_tool::{StaticTool, StaticToolContext, StaticToolError};
6use steer_tools::result::AstGrepResult;
7use steer_tools::tools::astgrep::{AstGrepError, AstGrepParams, AstGrepToolSpec};
8use steer_workspace::{AstGrepRequest, WorkspaceOpContext};
9
10pub struct AstGrepTool;
11
12#[async_trait]
13impl StaticTool for AstGrepTool {
14    type Params = AstGrepParams;
15    type Output = AstGrepResult;
16    type Spec = AstGrepToolSpec;
17
18    const DESCRIPTION: &'static str = r#"Structural code search using abstract syntax trees (AST).
19- Searches code by its syntactic structure, not just text patterns
20- Use $METAVAR placeholders (e.g., $VAR, $FUNC, $ARGS) to match any code element
21- Supports all major languages: rust, javascript, typescript, python, java, go, etc.
22Pattern examples:
23- "console.log($MSG)" - finds all console.log calls regardless of argument
24- "fn $NAME($PARAMS) { $BODY }" - finds all Rust function definitions
25- "if $COND { $THEN } else { $ELSE }" - finds all if-else statements
26- "import $WHAT from '$MODULE'" - finds all ES6 imports from specific modules
27- "$VAR = $VAR + $EXPR" - finds all self-incrementing assignments
28Advanced patterns:
29- "function $FUNC($$$ARGS) { $$$ }" - $$$ matches any number of elements
30- "foo($ARG, ...)" - ellipsis matches remaining arguments
31- Use any valid code as a pattern - ast-grep understands the syntax!
32Automatically respects .gitignore files"#;
33    const REQUIRES_APPROVAL: bool = false;
34    const REQUIRED_CAPABILITIES: Capabilities = Capabilities::WORKSPACE;
35
36    async fn execute(
37        &self,
38        params: Self::Params,
39        ctx: &StaticToolContext,
40    ) -> Result<Self::Output, StaticToolError<AstGrepError>> {
41        let request = AstGrepRequest {
42            pattern: params.pattern,
43            lang: params.lang,
44            include: params.include,
45            exclude: params.exclude,
46            path: params.path,
47        };
48        let op_ctx =
49            WorkspaceOpContext::new(ctx.tool_call_id.0.clone(), ctx.cancellation_token.clone());
50        let result = ctx
51            .services
52            .workspace
53            .astgrep(request, &op_ctx)
54            .await
55            .map_err(|e| {
56                StaticToolError::execution(AstGrepError::Workspace(workspace_op_error(e)))
57            })?;
58        Ok(AstGrepResult(result))
59    }
60}