use rig::tool::{Tool, ToolContext};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::path::{Path, PathBuf};
#[derive(Deserialize, Serialize)]
pub struct ListDirArgs {
path: PathBuf,
start: Option<usize>,
}
#[derive(Deserialize, Serialize)]
pub struct ListDir {
base_dir: PathBuf,
#[serde(default)]
max_results: Option<usize>,
}
impl ListDir {
pub fn new(base_dir: &Path, max_results: Option<usize>) -> Self {
Self {
base_dir: base_dir.to_path_buf(),
max_results,
}
}
}
impl Tool for ListDir {
const NAME: &'static str = "list_dir";
type Error = super::ToolError;
type Args = ListDirArgs;
type Output = super::DirectoryListing;
async fn call(
&self,
_context: &mut ToolContext,
args: Self::Args,
) -> Result<Self::Output, Self::Error> {
let path = super::allowed_canonical_path(&args.path, &self.base_dir)?;
let mut result = super::list_dir(&path, false)?;
result.total_entries = result.entries.len();
if let Some(max_results) = self.max_results
&& result.entries.len() > max_results
{
result.entries.truncate(max_results);
result.truncated = true;
}
Ok(result)
}
fn description(&self) -> String {
format!(
"List the files and directories in the given directory (relative to workspace root), \
returning {} entries. Use an empty string \"\" for the workspace root. \
Results include both files and subdirectories with their types.",
match self.max_results {
Some(val) => format!("at most {}", val),
None => "all".to_string(),
}
)
}
fn parameters(&self) -> serde_json::Value {
json!({
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Path to the directory relative to project root directory. \
Use an empty string for the root directory."
},
"max_results": {
"type": "integer",
"description": "Optional, limit the number of entries to return to at most the given value."
},
},
"required": ["path"]
})
}
fn map_error(&self, error: Self::Error) -> rig::tool::ToolExecutionError {
rig::tool::ToolExecutionError::from_error(error)
}
}
#[tokio::test]
async fn test_list_dir() {
let base_dir = std::env::current_dir().expect("Cannot get current directory");
let ld = ListDir::new(&base_dir, Some(100));
let result = ld
.call(
&mut ToolContext::default(),
ListDirArgs {
path: PathBuf::from(""),
start: None,
},
)
.await
.unwrap();
println!("Result: {:?}", result.total_entries);
}