diff --git a/codex-rs/core/src/tools/handlers/list_dir.rs b/codex-rs/core/src/tools/handlers/list_dir.rs deleted file mode 100644 index 047906003..000000000 --- a/codex-rs/core/src/tools/handlers/list_dir.rs +++ /dev/null @@ -1,294 +0,0 @@ -use std::collections::VecDeque; -use std::ffi::OsStr; -use std::fs::FileType; -use std::path::Path; -use std::path::PathBuf; - -use codex_protocol::permissions::ReadDenyMatcher; -use codex_utils_string::take_bytes_at_char_boundary; -use serde::Deserialize; -use tokio::fs; - -use crate::function_tool::FunctionCallError; -use crate::tools::context::FunctionToolOutput; -use crate::tools::context::ToolInvocation; -use crate::tools::context::ToolPayload; -use crate::tools::handlers::parse_arguments; -use crate::tools::registry::ToolHandler; -use crate::tools::registry::ToolKind; - -pub struct ListDirHandler; - -const DENY_READ_POLICY_MESSAGE: &str = - "access denied: reading this path is blocked by filesystem deny_read policy"; -const MAX_ENTRY_LENGTH: usize = 500; -const INDENTATION_SPACES: usize = 2; - -fn default_offset() -> usize { - 1 -} - -fn default_limit() -> usize { - 25 -} - -fn default_depth() -> usize { - 2 -} - -#[derive(Deserialize)] -struct ListDirArgs { - dir_path: String, - #[serde(default = "default_offset")] - offset: usize, - #[serde(default = "default_limit")] - limit: usize, - #[serde(default = "default_depth")] - depth: usize, -} - -impl ToolHandler for ListDirHandler { - type Output = FunctionToolOutput; - - fn kind(&self) -> ToolKind { - ToolKind::Function - } - - async fn handle(&self, invocation: ToolInvocation) -> Result { - let ToolInvocation { payload, turn, .. } = invocation; - - let arguments = match payload { - ToolPayload::Function { arguments } => arguments, - _ => { - return Err(FunctionCallError::RespondToModel( - "list_dir handler received unsupported payload".to_string(), - )); - } - }; - - let args: ListDirArgs = parse_arguments(&arguments)?; - - let ListDirArgs { - dir_path, - offset, - limit, - depth, - } = args; - - if offset == 0 { - return Err(FunctionCallError::RespondToModel( - "offset must be a 1-indexed entry number".to_string(), - )); - } - - if limit == 0 { - return Err(FunctionCallError::RespondToModel( - "limit must be greater than zero".to_string(), - )); - } - - if depth == 0 { - return Err(FunctionCallError::RespondToModel( - "depth must be greater than zero".to_string(), - )); - } - - let path = PathBuf::from(&dir_path); - if !path.is_absolute() { - return Err(FunctionCallError::RespondToModel( - "dir_path must be an absolute path".to_string(), - )); - } - let file_system_sandbox_policy = turn.file_system_sandbox_policy(); - let read_deny_matcher = ReadDenyMatcher::new(&file_system_sandbox_policy, &turn.cwd); - if read_deny_matcher - .as_ref() - .is_some_and(|matcher| matcher.is_read_denied(&path)) - { - return Err(FunctionCallError::RespondToModel(format!( - "{DENY_READ_POLICY_MESSAGE}: `{}`", - path.display() - ))); - } - - let entries = - list_dir_slice_with_policy(&path, offset, limit, depth, read_deny_matcher.as_ref()) - .await?; - let mut output = Vec::with_capacity(entries.len() + 1); - output.push(format!("Absolute path: {}", path.display())); - output.extend(entries); - Ok(FunctionToolOutput::from_text(output.join("\n"), Some(true))) - } -} - -async fn list_dir_slice_with_policy( - path: &Path, - offset: usize, - limit: usize, - depth: usize, - read_deny_matcher: Option<&ReadDenyMatcher>, -) -> Result, FunctionCallError> { - let mut entries = Vec::new(); - collect_entries(path, Path::new(""), depth, read_deny_matcher, &mut entries).await?; - - if entries.is_empty() { - return Ok(Vec::new()); - } - - entries.sort_unstable_by(|a, b| a.name.cmp(&b.name)); - - let start_index = offset - 1; - if start_index >= entries.len() { - return Err(FunctionCallError::RespondToModel( - "offset exceeds directory entry count".to_string(), - )); - } - - let remaining_entries = entries.len() - start_index; - let capped_limit = limit.min(remaining_entries); - let end_index = start_index + capped_limit; - let selected_entries = &entries[start_index..end_index]; - let mut formatted = Vec::with_capacity(selected_entries.len()); - - for entry in selected_entries { - formatted.push(format_entry_line(entry)); - } - - if end_index < entries.len() { - formatted.push(format!("More than {capped_limit} entries found")); - } - - Ok(formatted) -} - -async fn collect_entries( - dir_path: &Path, - relative_prefix: &Path, - depth: usize, - read_deny_matcher: Option<&ReadDenyMatcher>, - entries: &mut Vec, -) -> Result<(), FunctionCallError> { - let mut queue = VecDeque::new(); - queue.push_back((dir_path.to_path_buf(), relative_prefix.to_path_buf(), depth)); - - while let Some((current_dir, prefix, remaining_depth)) = queue.pop_front() { - let mut read_dir = fs::read_dir(¤t_dir).await.map_err(|err| { - FunctionCallError::RespondToModel(format!("failed to read directory: {err}")) - })?; - - let mut dir_entries = Vec::new(); - - while let Some(entry) = read_dir.next_entry().await.map_err(|err| { - FunctionCallError::RespondToModel(format!("failed to read directory: {err}")) - })? { - let entry_path = entry.path(); - if let Some(read_deny_matcher) = read_deny_matcher - && read_deny_matcher.is_read_denied(&entry_path) - { - continue; - } - - let file_type = entry.file_type().await.map_err(|err| { - FunctionCallError::RespondToModel(format!("failed to inspect entry: {err}")) - })?; - - let file_name = entry.file_name(); - let relative_path = if prefix.as_os_str().is_empty() { - PathBuf::from(&file_name) - } else { - prefix.join(&file_name) - }; - - let display_name = format_entry_component(&file_name); - let display_depth = prefix.components().count(); - let sort_key = format_entry_name(&relative_path); - let kind = DirEntryKind::from(&file_type); - dir_entries.push(( - entry_path, - relative_path, - kind, - DirEntry { - name: sort_key, - display_name, - depth: display_depth, - kind, - }, - )); - } - - dir_entries.sort_unstable_by(|a, b| a.3.name.cmp(&b.3.name)); - - for (entry_path, relative_path, kind, dir_entry) in dir_entries { - if kind == DirEntryKind::Directory && remaining_depth > 1 { - queue.push_back((entry_path, relative_path, remaining_depth - 1)); - } - entries.push(dir_entry); - } - } - - Ok(()) -} - -fn format_entry_name(path: &Path) -> String { - let normalized = path.to_string_lossy().replace("\\", "/"); - if normalized.len() > MAX_ENTRY_LENGTH { - take_bytes_at_char_boundary(&normalized, MAX_ENTRY_LENGTH).to_string() - } else { - normalized - } -} - -fn format_entry_component(name: &OsStr) -> String { - let normalized = name.to_string_lossy(); - if normalized.len() > MAX_ENTRY_LENGTH { - take_bytes_at_char_boundary(&normalized, MAX_ENTRY_LENGTH).to_string() - } else { - normalized.to_string() - } -} - -fn format_entry_line(entry: &DirEntry) -> String { - let indent = " ".repeat(entry.depth * INDENTATION_SPACES); - let mut name = entry.display_name.clone(); - match entry.kind { - DirEntryKind::Directory => name.push('/'), - DirEntryKind::Symlink => name.push('@'), - DirEntryKind::Other => name.push('?'), - DirEntryKind::File => {} - } - format!("{indent}{name}") -} - -#[derive(Clone)] -struct DirEntry { - name: String, - display_name: String, - depth: usize, - kind: DirEntryKind, -} - -#[derive(Clone, Copy, PartialEq, Eq)] -enum DirEntryKind { - Directory, - File, - Symlink, - Other, -} - -impl From<&FileType> for DirEntryKind { - fn from(file_type: &FileType) -> Self { - if file_type.is_symlink() { - DirEntryKind::Symlink - } else if file_type.is_dir() { - DirEntryKind::Directory - } else if file_type.is_file() { - DirEntryKind::File - } else { - DirEntryKind::Other - } - } -} - -#[cfg(test)] -#[path = "list_dir_tests.rs"] -mod tests; diff --git a/codex-rs/core/src/tools/handlers/list_dir_tests.rs b/codex-rs/core/src/tools/handlers/list_dir_tests.rs deleted file mode 100644 index 7de107a18..000000000 --- a/codex-rs/core/src/tools/handlers/list_dir_tests.rs +++ /dev/null @@ -1,331 +0,0 @@ -use super::*; -use codex_protocol::permissions::FileSystemAccessMode; -use codex_protocol::permissions::FileSystemPath; -use codex_protocol::permissions::FileSystemSandboxEntry; -use codex_protocol::permissions::FileSystemSandboxPolicy; -use codex_protocol::permissions::ReadDenyMatcher; -use pretty_assertions::assert_eq; -use tempfile::tempdir; - -async fn list_dir_slice( - path: &Path, - offset: usize, - limit: usize, - depth: usize, -) -> Result, FunctionCallError> { - list_dir_slice_with_policy(path, offset, limit, depth, /*read_deny_matcher*/ None).await -} - -#[tokio::test] -async fn lists_directory_entries() { - let temp = tempdir().expect("create tempdir"); - let dir_path = temp.path(); - - let sub_dir = dir_path.join("nested"); - tokio::fs::create_dir(&sub_dir) - .await - .expect("create sub dir"); - - let deeper_dir = sub_dir.join("deeper"); - tokio::fs::create_dir(&deeper_dir) - .await - .expect("create deeper dir"); - - tokio::fs::write(dir_path.join("entry.txt"), b"content") - .await - .expect("write file"); - tokio::fs::write(sub_dir.join("child.txt"), b"child") - .await - .expect("write child"); - tokio::fs::write(deeper_dir.join("grandchild.txt"), b"grandchild") - .await - .expect("write grandchild"); - - #[cfg(unix)] - { - use std::os::unix::fs::symlink; - let link_path = dir_path.join("link"); - symlink(dir_path.join("entry.txt"), &link_path).expect("create symlink"); - } - - let entries = list_dir_slice( - dir_path, /*offset*/ 1, /*limit*/ 20, /*depth*/ 3, - ) - .await - .expect("list directory"); - - #[cfg(unix)] - let expected = vec![ - "entry.txt".to_string(), - "link@".to_string(), - "nested/".to_string(), - " child.txt".to_string(), - " deeper/".to_string(), - " grandchild.txt".to_string(), - ]; - - #[cfg(not(unix))] - let expected = vec![ - "entry.txt".to_string(), - "nested/".to_string(), - " child.txt".to_string(), - " deeper/".to_string(), - " grandchild.txt".to_string(), - ]; - - assert_eq!(entries, expected); -} - -#[tokio::test] -async fn errors_when_offset_exceeds_entries() { - let temp = tempdir().expect("create tempdir"); - let dir_path = temp.path(); - tokio::fs::create_dir(dir_path.join("nested")) - .await - .expect("create sub dir"); - - let err = list_dir_slice( - dir_path, /*offset*/ 10, /*limit*/ 1, /*depth*/ 2, - ) - .await - .expect_err("offset exceeds entries"); - assert_eq!( - err, - FunctionCallError::RespondToModel("offset exceeds directory entry count".to_string()) - ); -} - -#[tokio::test] -async fn respects_depth_parameter() { - let temp = tempdir().expect("create tempdir"); - let dir_path = temp.path(); - let nested = dir_path.join("nested"); - let deeper = nested.join("deeper"); - tokio::fs::create_dir(&nested).await.expect("create nested"); - tokio::fs::create_dir(&deeper).await.expect("create deeper"); - tokio::fs::write(dir_path.join("root.txt"), b"root") - .await - .expect("write root"); - tokio::fs::write(nested.join("child.txt"), b"child") - .await - .expect("write nested"); - tokio::fs::write(deeper.join("grandchild.txt"), b"deep") - .await - .expect("write deeper"); - - let entries_depth_one = list_dir_slice( - dir_path, /*offset*/ 1, /*limit*/ 10, /*depth*/ 1, - ) - .await - .expect("list depth 1"); - assert_eq!( - entries_depth_one, - vec!["nested/".to_string(), "root.txt".to_string(),] - ); - - let entries_depth_two = list_dir_slice( - dir_path, /*offset*/ 1, /*limit*/ 20, /*depth*/ 2, - ) - .await - .expect("list depth 2"); - assert_eq!( - entries_depth_two, - vec![ - "nested/".to_string(), - " child.txt".to_string(), - " deeper/".to_string(), - "root.txt".to_string(), - ] - ); - - let entries_depth_three = list_dir_slice( - dir_path, /*offset*/ 1, /*limit*/ 30, /*depth*/ 3, - ) - .await - .expect("list depth 3"); - assert_eq!( - entries_depth_three, - vec![ - "nested/".to_string(), - " child.txt".to_string(), - " deeper/".to_string(), - " grandchild.txt".to_string(), - "root.txt".to_string(), - ] - ); -} - -#[tokio::test] -async fn paginates_in_sorted_order() { - let temp = tempdir().expect("create tempdir"); - let dir_path = temp.path(); - - let dir_a = dir_path.join("a"); - let dir_b = dir_path.join("b"); - tokio::fs::create_dir(&dir_a).await.expect("create a"); - tokio::fs::create_dir(&dir_b).await.expect("create b"); - - tokio::fs::write(dir_a.join("a_child.txt"), b"a") - .await - .expect("write a child"); - tokio::fs::write(dir_b.join("b_child.txt"), b"b") - .await - .expect("write b child"); - - let first_page = list_dir_slice( - dir_path, /*offset*/ 1, /*limit*/ 2, /*depth*/ 2, - ) - .await - .expect("list page one"); - assert_eq!( - first_page, - vec![ - "a/".to_string(), - " a_child.txt".to_string(), - "More than 2 entries found".to_string() - ] - ); - - let second_page = list_dir_slice( - dir_path, /*offset*/ 3, /*limit*/ 2, /*depth*/ 2, - ) - .await - .expect("list page two"); - assert_eq!( - second_page, - vec!["b/".to_string(), " b_child.txt".to_string()] - ); -} - -#[tokio::test] -async fn handles_large_limit_without_overflow() { - let temp = tempdir().expect("create tempdir"); - let dir_path = temp.path(); - tokio::fs::write(dir_path.join("alpha.txt"), b"alpha") - .await - .expect("write alpha"); - tokio::fs::write(dir_path.join("beta.txt"), b"beta") - .await - .expect("write beta"); - tokio::fs::write(dir_path.join("gamma.txt"), b"gamma") - .await - .expect("write gamma"); - - let entries = list_dir_slice(dir_path, /*offset*/ 2, usize::MAX, /*depth*/ 1) - .await - .expect("list without overflow"); - assert_eq!( - entries, - vec!["beta.txt".to_string(), "gamma.txt".to_string(),] - ); -} - -#[tokio::test] -async fn indicates_truncated_results() { - let temp = tempdir().expect("create tempdir"); - let dir_path = temp.path(); - - for idx in 0..40 { - let file = dir_path.join(format!("file_{idx:02}.txt")); - tokio::fs::write(file, b"content") - .await - .expect("write file"); - } - - let entries = list_dir_slice( - dir_path, /*offset*/ 1, /*limit*/ 25, /*depth*/ 1, - ) - .await - .expect("list directory"); - assert_eq!(entries.len(), 26); - assert_eq!( - entries.last(), - Some(&"More than 25 entries found".to_string()) - ); -} - -#[tokio::test] -async fn truncation_respects_sorted_order() -> anyhow::Result<()> { - let temp = tempdir()?; - let dir_path = temp.path(); - let nested = dir_path.join("nested"); - let deeper = nested.join("deeper"); - tokio::fs::create_dir(&nested).await?; - tokio::fs::create_dir(&deeper).await?; - tokio::fs::write(dir_path.join("root.txt"), b"root").await?; - tokio::fs::write(nested.join("child.txt"), b"child").await?; - tokio::fs::write(deeper.join("grandchild.txt"), b"deep").await?; - - let entries_depth_three = list_dir_slice( - dir_path, /*offset*/ 1, /*limit*/ 3, /*depth*/ 3, - ) - .await?; - assert_eq!( - entries_depth_three, - vec![ - "nested/".to_string(), - " child.txt".to_string(), - " deeper/".to_string(), - "More than 3 entries found".to_string() - ] - ); - - Ok(()) -} - -#[tokio::test] -async fn hides_denied_entries_and_prunes_denied_subtrees() { - let temp = tempdir().expect("create tempdir"); - let dir_path = temp.path(); - let visible_dir = dir_path.join("visible"); - let denied_dir = dir_path.join("private"); - tokio::fs::create_dir(&visible_dir) - .await - .expect("create visible dir"); - tokio::fs::create_dir(&denied_dir) - .await - .expect("create denied dir"); - tokio::fs::write(visible_dir.join("ok.txt"), b"ok") - .await - .expect("write visible file"); - tokio::fs::write(denied_dir.join("secret.txt"), b"secret") - .await - .expect("write denied file"); - tokio::fs::write(dir_path.join("top_secret.txt"), b"secret") - .await - .expect("write denied top-level file"); - - let policy = FileSystemSandboxPolicy::restricted(vec![ - FileSystemSandboxEntry { - path: FileSystemPath::Path { - path: denied_dir.try_into().expect("absolute denied dir"), - }, - access: FileSystemAccessMode::None, - }, - FileSystemSandboxEntry { - path: FileSystemPath::Path { - path: dir_path - .join("top_secret.txt") - .try_into() - .expect("absolute denied file"), - }, - access: FileSystemAccessMode::None, - }, - ]); - - let read_deny_matcher = ReadDenyMatcher::new(&policy, dir_path); - let entries = list_dir_slice_with_policy( - dir_path, - /*offset*/ 1, - /*limit*/ 20, - /*depth*/ 3, - read_deny_matcher.as_ref(), - ) - .await - .expect("list directory"); - - assert_eq!( - entries, - vec!["visible/".to_string(), " ok.txt".to_string(),] - ); -} diff --git a/codex-rs/core/src/tools/handlers/mod.rs b/codex-rs/core/src/tools/handlers/mod.rs index f7ad4f7e6..f713baffb 100644 --- a/codex-rs/core/src/tools/handlers/mod.rs +++ b/codex-rs/core/src/tools/handlers/mod.rs @@ -2,7 +2,6 @@ pub(crate) mod agent_jobs; pub(crate) mod apply_patch; mod dynamic; mod goal; -mod list_dir; mod mcp; mod mcp_resource; pub(crate) mod multi_agents; @@ -38,7 +37,6 @@ use codex_protocol::models::AdditionalPermissionProfile; use codex_protocol::protocol::AskForApproval; pub use dynamic::DynamicToolHandler; pub use goal::GoalHandler; -pub use list_dir::ListDirHandler; pub use mcp::McpHandler; pub use mcp_resource::McpResourceHandler; pub use plan::PlanHandler; diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index 53cb34f7a..83e8600e0 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -78,7 +78,6 @@ pub(crate) fn build_specs_with_discoverable_tools( use crate::tools::handlers::CodeModeWaitHandler; use crate::tools::handlers::DynamicToolHandler; use crate::tools::handlers::GoalHandler; - use crate::tools::handlers::ListDirHandler; use crate::tools::handlers::McpHandler; use crate::tools::handlers::McpResourceHandler; use crate::tools::handlers::PlanHandler; @@ -223,9 +222,6 @@ pub(crate) fn build_specs_with_discoverable_tools( ToolHandlerKind::ListAgentsV2 => { builder.register_handler(handler.name, Arc::new(ListAgentsHandlerV2)); } - ToolHandlerKind::ListDir => { - builder.register_handler(handler.name, Arc::new(ListDirHandler)); - } ToolHandlerKind::Mcp => { builder.register_handler(handler.name, mcp_handler.clone()); } diff --git a/codex-rs/tools/README.md b/codex-rs/tools/README.md index b85f8b219..9fa9b4543 100644 --- a/codex-rs/tools/README.md +++ b/codex-rs/tools/README.md @@ -22,7 +22,7 @@ schema and Responses API tool primitives that no longer need to live in - `ResponsesApiNamespace` - `ResponsesApiNamespaceTool` - code-mode `ToolSpec` adapters and `exec` / `wait` spec builders -- MCP resource, `list_dir`, and `test_sync_tool` spec builders +- MCP resource and `test_sync_tool` spec builders - local host tool spec builders for shell/exec/request-permissions/view-image - collaboration and agent-job `ToolSpec` builders for spawn/send/wait/close, `request_user_input`, and CSV fanout/reporting diff --git a/codex-rs/tools/src/lib.rs b/codex-rs/tools/src/lib.rs index 387d0394a..ebe54c382 100644 --- a/codex-rs/tools/src/lib.rs +++ b/codex-rs/tools/src/lib.rs @@ -150,7 +150,6 @@ pub use tool_spec::create_image_generation_tool; pub use tool_spec::create_local_shell_tool; pub use tool_spec::create_tools_json_for_responses_api; pub use tool_spec::create_web_search_tool; -pub use utility_tool::create_list_dir_tool; pub use utility_tool::create_test_sync_tool; pub use view_image::ViewImageToolOptions; pub use view_image::create_view_image_tool; diff --git a/codex-rs/tools/src/tool_registry_plan.rs b/codex-rs/tools/src/tool_registry_plan.rs index 8fa257b1e..cba5a4baf 100644 --- a/codex-rs/tools/src/tool_registry_plan.rs +++ b/codex-rs/tools/src/tool_registry_plan.rs @@ -32,7 +32,6 @@ use crate::create_followup_task_tool; use crate::create_get_goal_tool; use crate::create_image_generation_tool; use crate::create_list_agents_tool; -use crate::create_list_dir_tool; use crate::create_list_mcp_resource_templates_tool; use crate::create_list_mcp_resources_tool; use crate::create_local_shell_tool; @@ -348,20 +347,6 @@ pub fn build_tool_registry_plan( plan.register_handler("apply_patch", ToolHandlerKind::ApplyPatch); } - if config.environment_mode.has_environment() - && config - .experimental_supported_tools - .iter() - .any(|tool| tool == "list_dir") - { - plan.push_spec( - create_list_dir_tool(), - /*supports_parallel_tool_calls*/ true, - config.code_mode_enabled, - ); - plan.register_handler("list_dir", ToolHandlerKind::ListDir); - } - if config .experimental_supported_tools .iter() diff --git a/codex-rs/tools/src/tool_registry_plan_tests.rs b/codex-rs/tools/src/tool_registry_plan_tests.rs index 6f48a9e3b..264a2e5c7 100644 --- a/codex-rs/tools/src/tool_registry_plan_tests.rs +++ b/codex-rs/tools/src/tool_registry_plan_tests.rs @@ -535,7 +535,7 @@ fn disabled_environment_omits_environment_backed_tools() { let mut features = Features::with_defaults(); features.enable(Feature::UnifiedExec); let available_models = Vec::new(); - let mut tools_config = ToolsConfig::new(&ToolsConfigParams { + let tools_config = ToolsConfig::new(&ToolsConfigParams { model_info: &model_info, available_models: &available_models, features: &features, @@ -546,9 +546,6 @@ fn disabled_environment_omits_environment_backed_tools() { windows_sandbox_level: WindowsSandboxLevel::Disabled, }) .with_environment_mode(ToolEnvironmentMode::None); - tools_config - .experimental_supported_tools - .push("list_dir".to_string()); let (tools, _) = build_specs( &tools_config, /*mcp_tools*/ None, @@ -559,7 +556,6 @@ fn disabled_environment_omits_environment_backed_tools() { assert_lacks_tool_name(&tools, "exec_command"); assert_lacks_tool_name(&tools, "write_stdin"); assert_lacks_tool_name(&tools, "apply_patch"); - assert_lacks_tool_name(&tools, "list_dir"); assert_lacks_tool_name(&tools, VIEW_IMAGE_TOOL_NAME); } diff --git a/codex-rs/tools/src/tool_registry_plan_types.rs b/codex-rs/tools/src/tool_registry_plan_types.rs index 7c3772783..260194253 100644 --- a/codex-rs/tools/src/tool_registry_plan_types.rs +++ b/codex-rs/tools/src/tool_registry_plan_types.rs @@ -20,7 +20,6 @@ pub enum ToolHandlerKind { FollowupTaskV2, Goal, ListAgentsV2, - ListDir, Mcp, McpResource, Plan, diff --git a/codex-rs/tools/src/utility_tool.rs b/codex-rs/tools/src/utility_tool.rs index b0f93c972..0465a043e 100644 --- a/codex-rs/tools/src/utility_tool.rs +++ b/codex-rs/tools/src/utility_tool.rs @@ -3,42 +3,6 @@ use crate::ResponsesApiTool; use crate::ToolSpec; use std::collections::BTreeMap; -pub fn create_list_dir_tool() -> ToolSpec { - let properties = BTreeMap::from([ - ( - "dir_path".to_string(), - JsonSchema::string(Some("Absolute path to the directory to list.".to_string())), - ), - ( - "offset".to_string(), - JsonSchema::number(Some( - "The entry number to start listing from. Must be 1 or greater.".to_string(), - )), - ), - ( - "limit".to_string(), - JsonSchema::number(Some("The maximum number of entries to return.".to_string())), - ), - ( - "depth".to_string(), - JsonSchema::number(Some( - "The maximum directory depth to traverse. Must be 1 or greater.".to_string(), - )), - ), - ]); - - ToolSpec::Function(ResponsesApiTool { - name: "list_dir".to_string(), - description: - "Lists entries in a local directory with 1-indexed entry numbers and simple type labels." - .to_string(), - strict: false, - defer_loading: None, - parameters: JsonSchema::object(properties, Some(vec!["dir_path".to_string()]), Some(false.into())), - output_schema: None, - }) -} - pub fn create_test_sync_tool() -> ToolSpec { let barrier_properties = BTreeMap::from([ ( diff --git a/codex-rs/tools/src/utility_tool_tests.rs b/codex-rs/tools/src/utility_tool_tests.rs index 2984d02f4..97280315b 100644 --- a/codex-rs/tools/src/utility_tool_tests.rs +++ b/codex-rs/tools/src/utility_tool_tests.rs @@ -3,50 +3,6 @@ use crate::JsonSchema; use pretty_assertions::assert_eq; use std::collections::BTreeMap; -#[test] -fn list_dir_tool_matches_expected_spec() { - assert_eq!( - create_list_dir_tool(), - ToolSpec::Function(ResponsesApiTool { - name: "list_dir".to_string(), - description: - "Lists entries in a local directory with 1-indexed entry numbers and simple type labels." - .to_string(), - strict: false, - defer_loading: None, - parameters: JsonSchema::object(BTreeMap::from([ - ( - "depth".to_string(), - JsonSchema::number(Some( - "The maximum directory depth to traverse. Must be 1 or greater." - .to_string(), - )), - ), - ( - "dir_path".to_string(), - JsonSchema::string(Some( - "Absolute path to the directory to list.".to_string(), - )), - ), - ( - "limit".to_string(), - JsonSchema::number(Some( - "The maximum number of entries to return.".to_string(), - )), - ), - ( - "offset".to_string(), - JsonSchema::number(Some( - "The entry number to start listing from. Must be 1 or greater." - .to_string(), - )), - ), - ]), Some(vec!["dir_path".to_string()]), Some(false.into())), - output_schema: None, - }) - ); -} - #[test] fn test_sync_tool_matches_expected_spec() { assert_eq!(