From 76848e2f55ad4363fa7ce189e3800f74620baea5 Mon Sep 17 00:00:00 2001 From: Nicholas Clegg Date: Mon, 29 Sep 2025 14:06:59 -0400 Subject: [PATCH 1/2] fix: Tool watcher checks for tools repo even if initially missing --- src/strands/tools/registry.py | 6 +++++- src/strands/tools/watcher.py | 4 ++-- tests/strands/tools/test_watcher.py | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/strands/tools/registry.py b/src/strands/tools/registry.py index 0660337a2..e497c836c 100644 --- a/src/strands/tools/registry.py +++ b/src/strands/tools/registry.py @@ -246,7 +246,11 @@ def get_tools_dirs(self) -> List[Path]: tool_dirs.append(directory) logger.debug("tools_dir=<%s> | found tools directory", directory) else: - logger.debug("tools_dir=<%s> | tools directory not found", directory) + logger.debug( + "tools_dir=<%s> | tools directory not found." + "You must create a local tools directory to enable hot-reloading of tools", + directory, + ) return tool_dirs diff --git a/src/strands/tools/watcher.py b/src/strands/tools/watcher.py index 44f2ed512..0c2e63c05 100644 --- a/src/strands/tools/watcher.py +++ b/src/strands/tools/watcher.py @@ -86,7 +86,6 @@ def on_modified(self, event: Any) -> None: if event.src_path.endswith(".py"): tool_path = Path(event.src_path) tool_name = tool_path.stem - if tool_name not in ["__init__"]: # Delegate to all registered handlers for this directory for handler in ToolWatcher._registry_handlers.get(self.dir_path, {}).values(): @@ -122,7 +121,8 @@ def start(self) -> None: if dir_str not in ToolWatcher._watched_dirs: # First time seeing this directory, create a master handler master_handler = self.MasterChangeHandler(dir_str) - ToolWatcher._shared_observer.schedule(master_handler, dir_str, recursive=False) + + ToolWatcher._shared_observer.schedule(master_handler, str(tools_dir), recursive=False) ToolWatcher._watched_dirs.add(dir_str) logger.debug("tools_dir=<%s> | started watching tools directory", tools_dir) else: diff --git a/tests/strands/tools/test_watcher.py b/tests/strands/tools/test_watcher.py index 75a5616fe..01003520f 100644 --- a/tests/strands/tools/test_watcher.py +++ b/tests/strands/tools/test_watcher.py @@ -2,6 +2,7 @@ Tests for the SDK tool watcher module. """ +from pathlib import Path from unittest.mock import MagicMock, patch import pytest @@ -96,3 +97,24 @@ def test_on_modified_error_handling(mock_reload_tool): # Verify that reload_tool was called mock_reload_tool.assert_called_once_with("test_tool") + + +@patch("strands.tools.watcher.ToolWatcher._shared_observer") +@patch.object(ToolRegistry, "get_tools_dirs") +def test_start_uses_correct_path_for_observer_schedule(mock_get_tools_dirs, mock_observer): + """Test that start method schedules observer with correct path (str(tools_dir) not dir_str).""" + + # Mock the tools directories + tools_dir = Path("/test/tools") + mock_get_tools_dirs.return_value = [tools_dir] + + tool_registry = ToolRegistry() + watcher = ToolWatcher(tool_registry) + + # Call start method + watcher.start() + + # Verify that schedule was called with str(tools_dir) + mock_observer.schedule.assert_called_once() + args = mock_observer.schedule.call_args[0] + assert args[1] == str(tools_dir) # Second argument should be the string path From 280bd76254c45c646dec80cef301bc8ec6647c36 Mon Sep 17 00:00:00 2001 From: Nick Clegg Date: Tue, 30 Sep 2025 15:32:25 -0400 Subject: [PATCH 2/2] Update registry.py --- src/strands/tools/registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strands/tools/registry.py b/src/strands/tools/registry.py index e497c836c..53ec7b8d8 100644 --- a/src/strands/tools/registry.py +++ b/src/strands/tools/registry.py @@ -246,7 +246,7 @@ def get_tools_dirs(self) -> List[Path]: tool_dirs.append(directory) logger.debug("tools_dir=<%s> | found tools directory", directory) else: - logger.debug( + logger.warning( "tools_dir=<%s> | tools directory not found." "You must create a local tools directory to enable hot-reloading of tools", directory,