|
1 | 1 | import importlib |
| 2 | +import importlib.util |
2 | 3 | from pathlib import Path |
3 | 4 | from typing import Dict |
4 | 5 | from agentmesh.tools.base_tool import BaseTool |
@@ -40,50 +41,47 @@ def load_tools(self, tools_dir: str = "agentmesh/tools"): |
40 | 41 | print(f"Loaded {len(self.tools)} tools: {', '.join(self.tools.keys())}") |
41 | 42 |
|
42 | 43 | def _load_tools_from_directory(self, tools_dir: str): |
43 | | - """Dynamically load tools from directory""" |
| 44 | + """Dynamically load tools from directory using file loading""" |
44 | 45 | tools_path = Path(tools_dir) |
45 | | - for py_file in tools_path.rglob("*.py"): # Use rglob to recursively find .py files |
| 46 | + |
| 47 | + # Traverse all .py files |
| 48 | + for py_file in tools_path.rglob("*.py"): |
| 49 | + # Skip initialization files and base tool files |
46 | 50 | if py_file.name in ["__init__.py", "base_tool.py", "tool_manager.py"]: |
47 | 51 | continue |
48 | | - |
49 | | - # Construct the module name based on the relative path |
50 | | - plugin_name = py_file.stem |
51 | | - module_name = str(py_file.relative_to(Path(tools_dir).parent)).replace("/", ".").replace(".py", "") |
52 | | - # print(f"plugin_name: {plugin_name}, module_name: {module_name}") |
53 | | - |
54 | | - # Import using the corrected module name |
| 52 | + |
| 53 | + # Get module name |
| 54 | + module_name = py_file.stem |
| 55 | + |
55 | 56 | try: |
56 | | - module = importlib.import_module(f"agentmesh.{module_name}") # Ensure the correct base package |
57 | | - except ModuleNotFoundError as e: |
58 | | - # If browser_use dependency is missing, silently ignore |
59 | | - if "browser_use" in str(e): |
60 | | - # Optional: Print a more friendly message |
61 | | - # print(f"Skipping optional tool {module_name}: {e}") |
62 | | - continue |
63 | | - # Other import errors are printed |
64 | | - print(f"Error importing module {module_name}: {e}") |
65 | | - continue |
66 | | - |
67 | | - for attr_name in dir(module): |
68 | | - cls = getattr(module, attr_name) |
69 | | - if ( |
70 | | - isinstance(cls, type) |
71 | | - and issubclass(cls, BaseTool) |
72 | | - and cls != BaseTool |
73 | | - ): |
74 | | - try: |
75 | | - tool_instance = cls() |
76 | | - self.tools[tool_instance.name] = tool_instance |
77 | | - except TypeError as e: |
78 | | - print(f"Error initializing tool {cls.__name__}: {e}") |
79 | | - except ImportError as e: |
80 | | - # Catch tool initialization import errors |
81 | | - if "browser_use" in str(e): |
82 | | - # Optional: Print a more friendly message |
83 | | - # print(f"Skipping optional tool {cls.__name__}: {e}") |
84 | | - pass |
85 | | - else: |
86 | | - print(f"Error initializing tool {cls.__name__}: {e}") |
| 57 | + # Load module directly from file |
| 58 | + spec = importlib.util.spec_from_file_location(module_name, py_file) |
| 59 | + if spec and spec.loader: |
| 60 | + module = importlib.util.module_from_spec(spec) |
| 61 | + spec.loader.exec_module(module) |
| 62 | + |
| 63 | + # Find tool classes in the module |
| 64 | + for attr_name in dir(module): |
| 65 | + cls = getattr(module, attr_name) |
| 66 | + if ( |
| 67 | + isinstance(cls, type) |
| 68 | + and issubclass(cls, BaseTool) |
| 69 | + and cls != BaseTool |
| 70 | + ): |
| 71 | + try: |
| 72 | + # Instantiate tool and add to tool dictionary |
| 73 | + tool_instance = cls() |
| 74 | + self.tools[tool_instance.name] = tool_instance |
| 75 | + except ImportError as e: |
| 76 | + # Ignore browser_use dependency missing errors |
| 77 | + if "browser_use" in str(e): |
| 78 | + pass |
| 79 | + else: |
| 80 | + print(f"Error initializing tool {cls.__name__}: {e}") |
| 81 | + except Exception as e: |
| 82 | + print(f"Error initializing tool {cls.__name__}: {e}") |
| 83 | + except Exception as e: |
| 84 | + print(f"Error importing module {py_file}: {e}") |
87 | 85 |
|
88 | 86 | def _configure_tools_from_config(self): |
89 | 87 | """Configure tools based on configuration file""" |
|
0 commit comments