Skip to main content

steer_core/tools/static_tools/
grep.rs

1use async_trait::async_trait;
2use std::time::Duration;
3use tokio::time::timeout;
4
5use super::workspace_op_error;
6use crate::tools::capability::Capabilities;
7use crate::tools::static_tool::{StaticTool, StaticToolContext, StaticToolError};
8use steer_tools::result::GrepResult;
9use steer_tools::tools::grep::{GrepError, GrepParams, GrepToolSpec};
10use steer_workspace::{GrepRequest, WorkspaceOpContext};
11
12pub struct GrepTool;
13
14#[async_trait]
15impl StaticTool for GrepTool {
16    type Params = GrepParams;
17    type Output = GrepResult;
18    type Spec = GrepToolSpec;
19
20    const DESCRIPTION: &'static str = r#"Fast content search built on ripgrep for blazing performance at any scale.
21- Searches using regular expressions or literal strings
22- Supports regex syntax like "log.*Error", "function\\s+\\w+", etc.
23- If the pattern isn't valid regex, it automatically searches for the literal text
24- Filter files by name pattern with include parameter (e.g., "*.js", "*.{ts,tsx}")
25- Automatically respects .gitignore files
26- Returns matches as "filepath:line_number: line_content""#;
27    const REQUIRES_APPROVAL: bool = false;
28    const REQUIRED_CAPABILITIES: Capabilities = Capabilities::WORKSPACE;
29
30    async fn execute(
31        &self,
32        params: Self::Params,
33        ctx: &StaticToolContext,
34    ) -> Result<Self::Output, StaticToolError<GrepError>> {
35        const GREP_TIMEOUT: Duration = Duration::from_secs(30);
36
37        let request = GrepRequest {
38            pattern: params.pattern,
39            include: params.include,
40            path: params.path,
41        };
42        let op_ctx =
43            WorkspaceOpContext::new(ctx.tool_call_id.0.clone(), ctx.cancellation_token.clone());
44
45        tokio::select! {
46            () = ctx.cancellation_token.cancelled() => Err(StaticToolError::Cancelled),
47            result = timeout(GREP_TIMEOUT, ctx.services.workspace.grep(request, &op_ctx)) => {
48                match result {
49                    Ok(Ok(search_result)) => Ok(GrepResult(search_result)),
50                    Ok(Err(error)) => Err(StaticToolError::execution(GrepError::Workspace(workspace_op_error(error)))),
51                    Err(_) => Err(StaticToolError::Timeout),
52                }
53            }
54        }
55    }
56}