sgr-agent-tools 0.4.0

14 reusable file-system tools for sgr-agent based AI agents
Documentation
//! ReadAllTool — batch read all files in a directory.

use std::sync::Arc;

use schemars::JsonSchema;
use serde::Deserialize;
use serde_json::Value;
use sgr_agent_core::agent_tool::{Tool, ToolError, ToolOutput, parse_args};
use sgr_agent_core::context::AgentContext;
use sgr_agent_core::schema::json_schema_for;

use crate::backend::FileBackend;
use crate::helpers::backend_err;
use crate::trust::infer_trust;

pub struct ReadAllTool<B: FileBackend>(pub Arc<B>);

#[derive(Deserialize, JsonSchema)]
struct ReadAllArgs {
    /// Directory path to read all files from
    path: String,
}

#[async_trait::async_trait]
impl<B: FileBackend> Tool for ReadAllTool<B> {
    fn name(&self) -> &str {
        "read_all"
    }
    fn description(&self) -> &str {
        "Read ALL files in a directory in one call. Much faster than listing then reading one by one. Returns each file with its path header."
    }
    fn is_read_only(&self) -> bool {
        true
    }
    fn parameters_schema(&self) -> Value {
        json_schema_for::<ReadAllArgs>()
    }
    async fn execute(&self, args: Value, ctx: &mut AgentContext) -> Result<ToolOutput, ToolError> {
        self.execute_readonly(args, ctx).await
    }
    async fn execute_readonly(
        &self,
        args: Value,
        _ctx: &AgentContext,
    ) -> Result<ToolOutput, ToolError> {
        let a: ReadAllArgs = parse_args(&args)?;
        let listing = self.0.list(&a.path).await.map_err(backend_err)?;

        let mut output = String::new();
        let mut count = 0u32;
        for line in listing.lines().skip(1) {
            let name = line.trim();
            if name.is_empty() || name.ends_with('/') {
                continue;
            }
            let full_path = if a.path.ends_with('/') {
                format!("{}{}", a.path, name)
            } else {
                format!("{}/{}", a.path, name)
            };
            match self.0.read(&full_path, false, 0, 0).await {
                Ok(content) => {
                    let trust = infer_trust(&full_path);
                    output.push_str(&format!(
                        "--- {} [{}] ---\n{}\n\n",
                        full_path, trust, content
                    ));
                    count += 1;
                }
                Err(e) => {
                    output.push_str(&format!("--- {} ---\n[error: {}]\n\n", full_path, e));
                }
            }
        }
        if count == 0 {
            output.push_str("(no files found)\n");
        }
        Ok(ToolOutput::text(output))
    }
}