CoolFace
Apppublic

Backup-bdg/OpenHands

sourceHugging Faceapache-2.0updated 1y agoView on Hugging Face
0likes
agent.py184 linesDownload Raw Back to controller
1from __future__ import annotations2 3from abc import ABC, abstractmethod4from typing import TYPE_CHECKING5 6if TYPE_CHECKING:7    from openhands.controller.state.state import State8    from openhands.core.config import AgentConfig9    from openhands.events.action import Action10    from openhands.events.action.message import SystemMessageAction11    from openhands.utils.prompt import PromptManager12from litellm import ChatCompletionToolParam13 14from openhands.core.exceptions import (15    AgentAlreadyRegisteredError,16    AgentNotRegisteredError,17)18from openhands.core.logger import openhands_logger as logger19from openhands.events.event import EventSource20from openhands.llm.llm import LLM21from openhands.runtime.plugins import PluginRequirement22 23 24class Agent(ABC):25    DEPRECATED = False26    """27    This abstract base class is an general interface for an agent dedicated to28    executing a specific instruction and allowing human interaction with the29    agent during execution.30    It tracks the execution status and maintains a history of interactions.31    """32 33    _registry: dict[str, type['Agent']] = {}34    sandbox_plugins: list[PluginRequirement] = []35 36    def __init__(37        self,38        llm: LLM,39        config: 'AgentConfig',40    ):41        self.llm = llm42        self.config = config43        self._complete = False44        self._prompt_manager: 'PromptManager' | None = None45        self.mcp_tools: dict[str, ChatCompletionToolParam] = {}46        self.tools: list = []47 48    @property49    def prompt_manager(self) -> 'PromptManager':50        if self._prompt_manager is None:51            raise ValueError(f'Prompt manager not initialized for agent {self.name}')52        return self._prompt_manager53 54    def get_system_message(self) -> 'SystemMessageAction | None':55        """56        Returns a SystemMessageAction containing the system message and tools.57        This will be added to the event stream as the first message.58 59        Returns:60            SystemMessageAction: The system message action with content and tools61            None: If there was an error generating the system message62        """63        # Import here to avoid circular imports64        from openhands.events.action.message import SystemMessageAction65 66        try:67            if not self.prompt_manager:68                logger.warning(69                    f'[{self.name}] Prompt manager not initialized before getting system message'70                )71                return None72 73            system_message = self.prompt_manager.get_system_message()74 75            # Get tools if available76            tools = getattr(self, 'tools', None)77 78            system_message_action = SystemMessageAction(79                content=system_message, tools=tools, agent_class=self.name80            )81            # Set the source attribute82            system_message_action._source = EventSource.AGENT  # type: ignore83 84            return system_message_action85        except Exception as e:86            logger.warning(f'[{self.name}] Failed to generate system message: {e}')87            return None88 89    @property90    def complete(self) -> bool:91        """Indicates whether the current instruction execution is complete.92 93        Returns:94        - complete (bool): True if execution is complete; False otherwise.95        """96        return self._complete97 98    @abstractmethod99    def step(self, state: 'State') -> 'Action':100        """Starts the execution of the assigned instruction. This method should101        be implemented by subclasses to define the specific execution logic.102        """103        pass104 105    def reset(self) -> None:106        """Resets the agent's execution status and clears the history. This method can be used107        to prepare the agent for restarting the instruction or cleaning up before destruction.108 109        """110        # TODO clear history111        self._complete = False112 113        if self.llm:114            self.llm.reset()115 116    @property117    def name(self) -> str:118        return self.__class__.__name__119 120    @classmethod121    def register(cls, name: str, agent_cls: type['Agent']) -> None:122        """Registers an agent class in the registry.123 124        Parameters:125        - name (str): The name to register the class under.126        - agent_cls (Type['Agent']): The class to register.127 128        Raises:129        - AgentAlreadyRegisteredError: If name already registered130        """131        if name in cls._registry:132            raise AgentAlreadyRegisteredError(name)133        cls._registry[name] = agent_cls134 135    @classmethod136    def get_cls(cls, name: str) -> type['Agent']:137        """Retrieves an agent class from the registry.138 139        Parameters:140        - name (str): The name of the class to retrieve141 142        Returns:143        - agent_cls (Type['Agent']): The class registered under the specified name.144 145        Raises:146        - AgentNotRegisteredError: If name not registered147        """148        if name not in cls._registry:149            raise AgentNotRegisteredError(name)150        return cls._registry[name]151 152    @classmethod153    def list_agents(cls) -> list[str]:154        """Retrieves the list of all agent names from the registry.155 156        Raises:157        - AgentNotRegisteredError: If no agent is registered158        """159        if not bool(cls._registry):160            raise AgentNotRegisteredError()161        return list(cls._registry.keys())162 163    def set_mcp_tools(self, mcp_tools: list[dict]) -> None:164        """Sets the list of MCP tools for the agent.165 166        Args:167        - mcp_tools (list[dict]): The list of MCP tools.168        """169        logger.info(170            f'Setting {len(mcp_tools)} MCP tools for agent {self.name}: {[tool["function"]["name"] for tool in mcp_tools]}'171        )172        for tool in mcp_tools:173            _tool = ChatCompletionToolParam(**tool)174            if _tool['function']['name'] in self.mcp_tools:175                logger.warning(176                    f'Tool {_tool["function"]["name"]} already exists, skipping'177                )178                continue179            self.mcp_tools[_tool['function']['name']] = _tool180            self.tools.append(_tool)181        logger.info(182            f'Tools updated for agent {self.name}, total {len(self.tools)}: {[tool["function"]["name"] for tool in self.tools]}'183        )184