| from dataclasses import dataclass |
| from typing import Optional, Type |
| from abc import ABC |
| from importlib import import_module |
|
|
| from ..exceptions.exceptions import InvalidConfigException |
| from ..utils import Config |
|
|
|
|
| @dataclass |
| class BaseToolRequest(ABC): |
| input_text: Optional[str] |
|
|
|
|
| @dataclass |
| class BaseToolResponse(ABC): |
| output_text: Optional[str] |
|
|
|
|
| |
| class BaseTool(ABC): |
| _name = None |
| _description = None |
|
|
| def __init__(self, name, description, **kwargs): |
| self._name = name |
| self._description = description |
| self.setup() |
|
|
| @property |
| def name(self): |
| """Getter for name.""" |
| return self._name |
|
|
| @property |
| def description(self): |
| """Getter for description.""" |
| return self._description |
|
|
| @classmethod |
| def from_config(cls, config_input, **kwargs): |
| """Create a BaseTool instance from a config file path or a config data dictionary. |
| |
| :param config_input: Either a file path to a config file or a config data dictionary. |
| :type config_input: str or dict |
| :param kwargs: Additional keyword arguments to pass to the class constructor. |
| :return: A BaseTool instance. |
| :rtype: BaseTool |
| """ |
| if isinstance(config_input, str): |
| |
| config_data = Config.load(config_input) |
| elif isinstance(config_input, dict): |
| |
| config_data = config_input |
| else: |
| raise InvalidConfigException( |
| f"Invalid config_input type: {type(config_input)}. " |
| "Expected str (file path) or dict (config data)." |
| ) |
|
|
| module_name = config_data['module_name'] |
| class_name = config_data['class_name'] |
| module = import_module(module_name) |
| clazz = getattr(module, class_name) |
| return clazz(**config_data, **kwargs) |
|
|
| @classmethod |
| async def async_from_config(cls, config_input, **params): |
| """Asynchronously create a BaseTool instance from a config file path or a config data dictionary. |
| |
| :param config_input: Either a file path to a config file or a config data dictionary. |
| :type config_input: str or dict |
| :param params: Additional parameters to pass to the create method. |
| :return: A BaseTool instance. |
| :rtype: BaseTool |
| """ |
| |
|
|
| if isinstance(config_input, str): |
| |
| config_data = Config.load(config_input) |
| elif isinstance(config_input, dict): |
| |
| config_data = config_input |
| else: |
| raise InvalidConfigException( |
| f"Invalid config_input type: {type(config_input)}. " |
| "Expected str (file path) or dict (config data)." |
| ) |
|
|
| |
| module_name = config_data['module_name'] |
| class_name = config_data['class_name'] |
| module = import_module(module_name) |
| clazz = getattr(module, class_name) |
| |
| return await clazz.create(config_data, **params) |
|
|
| @classmethod |
| async def async_from_config_path(cls, config_path, **params): |
| return await cls.async_from_config_data(config_data=Config.load(config_path), **params) |
|
|
| @classmethod |
| async def async_from_config_data(cls, config_data, **params): |
| module_name = config_data['module_name'] |
| class_name = config_data['class_name'] |
|
|
| module = import_module(module_name) |
| clazz = getattr(module, class_name) |
|
|
| return await clazz.create(config_data, **params) |
|
|
| @classmethod |
| async def create(cls, config_data, **params): |
| """ |
| Async create tool instance. init cannot be async, so wrap async init logic here. |
| """ |
| pass |
|
|
| def setup(self): |
| pass |
|
|
| def run(self, req: BaseToolRequest): |
| pass |
|
|
| async def async_run(self, req: BaseToolRequest): |
| """ |
| Async run tool. |
| """ |
| return self.run(req) |
|
|