use anyhow::Result;
use async_trait::async_trait;
use serde_json::Value;
use std::path::Path;
use super::{Tool, ToolOutput};
use crate::tools::file_ops::{grep_search_in_workspace, GrepSearchInput};
pub struct GrepSearchTool;
impl GrepSearchTool {
pub fn new() -> Self {
Self
}
}
impl Default for GrepSearchTool {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl Tool for GrepSearchTool {
fn name(&self) -> &str {
"grep_search"
}
fn description(&self) -> &str {
"Search file contents with a regex pattern."
}
fn parameters_schema(&self) -> Value {
serde_json::json!({
"type": "object",
"properties": {
"pattern": { "type": "string" },
"path": { "type": "string" },
"glob": { "type": "string" },
"output_mode": { "type": "string" },
"-B": { "type": "integer", "minimum": 0 },
"-A": { "type": "integer", "minimum": 0 },
"-C": { "type": "integer", "minimum": 0 },
"context": { "type": "integer", "minimum": 0 },
"-n": { "type": "boolean" },
"-i": { "type": "boolean" },
"type": { "type": "string" },
"head_limit": { "type": "integer", "minimum": 1 },
"offset": { "type": "integer", "minimum": 0 },
"multiline": { "type": "boolean" }
},
"required": ["pattern"],
"additionalProperties": false
})
}
async fn execute(&self, input: Value) -> Result<ToolOutput> {
let grep_input: GrepSearchInput = serde_json::from_value(input)?;
let workspace_root = std::env::current_dir()?;
match grep_search_in_workspace(&grep_input, &workspace_root) {
Ok(output) => {
let serialized = serde_json::to_string_pretty(&output)?;
Ok(ToolOutput::success(serialized))
}
Err(e) => Ok(ToolOutput::error(format!("Error performing grep search: {}", e))),
}
}
}