11import importlib
2+ import importlib .util
23from pathlib import Path
34from typing import Dict
45from agentmesh .tools .base_tool import BaseTool
@@ -28,7 +29,7 @@ def __init__(self):
2829 def load_tools (self , tools_dir : str = "agentmesh/tools" ):
2930 """
3031 Load tools from both directory and configuration.
31-
32+
3233 :param tools_dir: Directory to scan for tool modules
3334 """
3435 # First, load tools from directory (for backward compatibility)
@@ -38,52 +39,49 @@ def load_tools(self, tools_dir: str = "agentmesh/tools"):
3839 self ._configure_tools_from_config ()
3940
4041 print (f"Loaded { len (self .tools )} tools: { ', ' .join (self .tools .keys ())} " )
41-
42+
4243 def _load_tools_from_directory (self , tools_dir : str ):
43- """Dynamically load tools from directory"""
44+ """Dynamically load tools from directory using file loading """
4445 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
4650 if py_file .name in ["__init__.py" , "base_tool.py" , "tool_manager.py" ]:
4751 continue
4852
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+ # Get module name
54+ module_name = py_file .stem
5355
54- # Import using the corrected module name
5556 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 } " )
8785
8886 def _configure_tools_from_config (self ):
8987 """Configure tools based on configuration file"""
@@ -120,7 +118,7 @@ def _configure_tools_from_config(self):
120118 def get_tool (self , name : str ) -> BaseTool :
121119 """
122120 Get a tool by name.
123-
121+
124122 :param name: The name of the tool to get.
125123 :return: The tool instance or None if not found.
126124 """
@@ -129,7 +127,7 @@ def get_tool(self, name: str) -> BaseTool:
129127 def list_tools (self ) -> dict :
130128 """
131129 Get information about all loaded tools.
132-
130+
133131 :return: A dictionary with tool information.
134132 """
135133 return {
0 commit comments