From d38e8b8f6c8a5a48f7664e03f5ea7df7f2a46324 Mon Sep 17 00:00:00 2001 From: Krzysztof Czerwinski <34861343+kcze@users.noreply.github.com> Date: Sun, 28 Apr 2024 21:10:53 +0200 Subject: [PATCH] clean(autogpt): Remove old plugin system (#7097) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Background Follow up after merging https://github.com/Significant-Gravitas/AutoGPT/pull/7054, old plugins will no longer be used. ### Changes 🏗️ - Removed all dead code needed to load and use plugins. - Removed `auto-gpt-plugin-template` dependency - Removed `rev=` from `autogpt-forge` dependency (the set `rev` had incompatible `duckduckgo-search` versions) - Kept `--install-plugin-deps` CLI option and dead code associated (may be needed for new plugins) --- autogpts/autogpt/.env.template | 3 - .../autogpt/agbenchmark_config/benchmarks.py | 1 - .../autogpt/agent_factory/configurators.py | 6 - autogpts/autogpt/autogpt/agents/base.py | 16 - .../agents/features/agent_file_manager.py | 1 - autogpts/autogpt/autogpt/app/main.py | 22 +- autogpts/autogpt/autogpt/app/utils.py | 30 +- autogpts/autogpt/autogpt/config/config.py | 48 +-- autogpts/autogpt/autogpt/logs/__init__.py | 3 +- autogpts/autogpt/autogpt/logs/config.py | 20 -- autogpts/autogpt/autogpt/logs/helpers.py | 6 +- .../autogpt/autogpt/memory/vector/utils.py | 18 - .../autogpt/models/base_open_ai_plugin.py | 251 ------------- autogpts/autogpt/autogpt/plugins/__init__.py | 330 ------------------ .../autogpt/autogpt/plugins/plugin_config.py | 11 - .../autogpt/autogpt/plugins/plugins_config.py | 118 ------- autogpts/autogpt/poetry.lock | 37 +- autogpts/autogpt/pyproject.toml | 3 +- .../autogpt/scripts/install_plugin_deps.py | 66 ---- autogpts/autogpt/tests/conftest.py | 29 -- .../tests/integration/agent_factory.py | 1 - .../Auto-GPT-Plugin-Test-master.zip | Bin 15385 -> 0 bytes .../test_plugins/auto_gpt_guanaco/__init__.py | 274 --------------- .../unit/models/test_base_open_api_plugin.py | 81 ----- autogpts/autogpt/tests/unit/test_plugins.py | 125 ------- docs/content/AutoGPT/configuration/options.md | 1 - 26 files changed, 11 insertions(+), 1490 deletions(-) delete mode 100644 autogpts/autogpt/autogpt/models/base_open_ai_plugin.py delete mode 100644 autogpts/autogpt/autogpt/plugins/__init__.py delete mode 100644 autogpts/autogpt/autogpt/plugins/plugin_config.py delete mode 100644 autogpts/autogpt/autogpt/plugins/plugins_config.py delete mode 100644 autogpts/autogpt/scripts/install_plugin_deps.py delete mode 100644 autogpts/autogpt/tests/unit/data/test_plugins/Auto-GPT-Plugin-Test-master.zip delete mode 100644 autogpts/autogpt/tests/unit/data/test_plugins/auto_gpt_guanaco/__init__.py delete mode 100644 autogpts/autogpt/tests/unit/models/test_base_open_api_plugin.py delete mode 100644 autogpts/autogpt/tests/unit/test_plugins.py diff --git a/autogpts/autogpt/.env.template b/autogpts/autogpt/.env.template index 7155e30284e..ba514c56b0c 100644 --- a/autogpts/autogpt/.env.template +++ b/autogpts/autogpt/.env.template @@ -44,9 +44,6 @@ OPENAI_API_KEY=your-openai-api-key ## AI_SETTINGS_FILE - Specifies which AI Settings file to use, relative to the AutoGPT root directory. (defaults to ai_settings.yaml) # AI_SETTINGS_FILE=ai_settings.yaml -## PLUGINS_CONFIG_FILE - The path to the plugins_config.yaml file, relative to the AutoGPT root directory. (Default plugins_config.yaml) -# PLUGINS_CONFIG_FILE=plugins_config.yaml - ## PROMPT_SETTINGS_FILE - Specifies which Prompt Settings file to use, relative to the AutoGPT root directory. (defaults to prompt_settings.yaml) # PROMPT_SETTINGS_FILE=prompt_settings.yaml diff --git a/autogpts/autogpt/agbenchmark_config/benchmarks.py b/autogpts/autogpt/agbenchmark_config/benchmarks.py index 98731109c20..1281f9fff6a 100644 --- a/autogpts/autogpt/agbenchmark_config/benchmarks.py +++ b/autogpts/autogpt/agbenchmark_config/benchmarks.py @@ -52,7 +52,6 @@ def bootstrap_agent(task: str, continuous_mode: bool) -> Agent: smart_llm=config.smart_llm, allow_fs_access=not config.restrict_to_workspace, use_functions_api=config.openai_functions, - plugins=config.plugins, ), prompt_config=agent_prompt_config, history=Agent.default_settings.history.copy(deep=True), diff --git a/autogpts/autogpt/autogpt/agent_factory/configurators.py b/autogpts/autogpt/autogpt/agent_factory/configurators.py index 19cec69ece7..b727beb99fc 100644 --- a/autogpts/autogpt/autogpt/agent_factory/configurators.py +++ b/autogpts/autogpt/autogpt/agent_factory/configurators.py @@ -4,8 +4,6 @@ from autogpt.config import AIDirectives, AIProfile, Config from autogpt.core.resource.model_providers import ChatModelProvider from autogpt.file_storage.base import FileStorage -from autogpt.logs.config import configure_chat_plugins -from autogpt.plugins import scan_plugins def create_agent( @@ -65,9 +63,6 @@ def _configure_agent( " must be specified" ) - app_config.plugins = scan_plugins(app_config) - configure_chat_plugins(app_config) - agent_state = state or create_agent_state( agent_id=agent_id, task=task, @@ -105,7 +100,6 @@ def create_agent_state( smart_llm=app_config.smart_llm, allow_fs_access=not app_config.restrict_to_workspace, use_functions_api=app_config.openai_functions, - plugins=app_config.plugins, ), history=Agent.default_settings.history.copy(deep=True), ) diff --git a/autogpts/autogpt/autogpt/agents/base.py b/autogpts/autogpt/autogpt/agents/base.py index 4d450a9a28f..e293441d857 100644 --- a/autogpts/autogpt/autogpt/agents/base.py +++ b/autogpts/autogpt/autogpt/agents/base.py @@ -15,7 +15,6 @@ overload, ) -from auto_gpt_plugin_template import AutoGPTPluginTemplate from colorama import Fore from pydantic import BaseModel, Field, validator @@ -96,21 +95,6 @@ class BaseAgentConfiguration(SystemConfiguration): summary_max_tlength: Optional[int] = None # TODO: move to ActionHistoryConfiguration - plugins: list[AutoGPTPluginTemplate] = Field(default_factory=list, exclude=True) - - class Config: - arbitrary_types_allowed = True # Necessary for plugins - - @validator("plugins", each_item=True) - def validate_plugins(cls, p: AutoGPTPluginTemplate | Any): - assert issubclass( - p.__class__, AutoGPTPluginTemplate - ), f"{p} does not subclass AutoGPTPluginTemplate" - assert ( - p.__class__.__name__ != "AutoGPTPluginTemplate" - ), f"Plugins must subclass AutoGPTPluginTemplate; {p} is a template instance" - return p - @validator("use_functions_api") def validate_openai_functions(cls, v: bool, values: dict[str, Any]): if v: diff --git a/autogpts/autogpt/autogpt/agents/features/agent_file_manager.py b/autogpts/autogpt/autogpt/agents/features/agent_file_manager.py index 3736e2e60c2..1df9edfe19c 100644 --- a/autogpts/autogpt/autogpt/agents/features/agent_file_manager.py +++ b/autogpts/autogpt/autogpt/agents/features/agent_file_manager.py @@ -135,7 +135,6 @@ async def write_to_file(self, filename: str | Path, contents: str) -> str: Returns: str: A message indicating success or failure """ - logger.info(f"self: {self}") if directory := os.path.dirname(filename): self.workspace.make_dir(directory) await self.workspace.write_file(filename, contents) diff --git a/autogpts/autogpt/autogpt/app/main.py b/autogpts/autogpt/autogpt/app/main.py index 9ff086369ce..f256c870788 100644 --- a/autogpts/autogpt/autogpt/app/main.py +++ b/autogpts/autogpt/autogpt/app/main.py @@ -37,13 +37,11 @@ from autogpt.core.resource.model_providers.openai import OpenAIProvider from autogpt.core.runner.client_lib.utils import coroutine from autogpt.file_storage import FileStorageBackendName, get_storage -from autogpt.logs.config import LoggingConfig, configure_chat_plugins, configure_logging +from autogpt.logs.config import configure_logging from autogpt.logs.helpers import print_attribute, speak from autogpt.models.action_history import ActionInterruptedByHuman -from autogpt.plugins import scan_plugins from autogpt.utils.exceptions import AgentTerminated, InvalidAgentResponseError from autogpt.utils.utils import DEFAULT_FINISH_COMMAND -from scripts.install_plugin_deps import install_plugin_dependencies from .configurator import apply_overrides_to_config from .setup import apply_overrides_to_ai_settings, interactively_revise_ai_settings @@ -166,12 +164,6 @@ async def run_auto_gpt( title_color=Fore.YELLOW, ) - if install_plugin_deps: - install_plugin_dependencies() - - config.plugins = scan_plugins(config) - configure_chat_plugins(config) - # Let user choose an existing agent to run agent_manager = AgentManager(file_storage) existing_agents = agent_manager.list_agents() @@ -408,11 +400,6 @@ async def run_auto_gpt_server( llm_provider = _configure_openai_provider(config) - if install_plugin_deps: - install_plugin_dependencies() - - config.plugins = scan_plugins(config) - # Set up & start server database = AgentDB( database_string=os.getenv("AP_SERVER_DB_URL", "sqlite:///data/ap_server.db"), @@ -726,12 +713,7 @@ async def get_user_feedback( while user_feedback is None: # Get input from user - if config.chat_messages_enabled: - console_input = clean_input(config, "Waiting for your response...") - else: - console_input = clean_input( - config, Fore.MAGENTA + "Input:" + Style.RESET_ALL - ) + console_input = clean_input(config, Fore.MAGENTA + "Input:" + Style.RESET_ALL) # Parse user input if console_input.lower().strip() == config.authorise_key: diff --git a/autogpts/autogpt/autogpt/app/utils.py b/autogpts/autogpt/autogpt/app/utils.py index 49a1e2a44fd..f1a89f490d5 100644 --- a/autogpts/autogpt/autogpt/app/utils.py +++ b/autogpts/autogpt/autogpt/app/utils.py @@ -20,34 +20,6 @@ def clean_input(config: "Config", prompt: str = ""): try: - if config.chat_messages_enabled: - for plugin in config.plugins: - if not hasattr(plugin, "can_handle_user_input"): - continue - if not plugin.can_handle_user_input(user_input=prompt): - continue - plugin_response = plugin.user_input(user_input=prompt) - if not plugin_response: - continue - if plugin_response.lower() in [ - "yes", - "yeah", - "y", - "ok", - "okay", - "sure", - "alright", - ]: - return config.authorise_key - elif plugin_response.lower() in [ - "no", - "nope", - "n", - "negative", - ]: - return config.exit_key - return plugin_response - # ask for input, default when just pressing Enter is y logger.debug("Asking user via keyboard...") @@ -215,7 +187,7 @@ def print_motd(config: "Config", logger: logging.Logger): }, msg=motd_line, ) - if is_new_motd and not config.chat_messages_enabled: + if is_new_motd: input( Fore.MAGENTA + Style.BRIGHT diff --git a/autogpts/autogpt/autogpt/config/config.py b/autogpts/autogpt/autogpt/config/config.py index 475ad745d2f..8dd648188d1 100644 --- a/autogpts/autogpt/autogpt/config/config.py +++ b/autogpts/autogpt/autogpt/config/config.py @@ -7,9 +7,8 @@ from pathlib import Path from typing import Any, Optional, Union -from auto_gpt_plugin_template import AutoGPTPluginTemplate from colorama import Fore -from pydantic import Field, SecretStr, validator +from pydantic import SecretStr, validator import autogpt from autogpt.app.utils import clean_input @@ -25,7 +24,6 @@ ) from autogpt.file_storage import FileStorageBackendName from autogpt.logs.config import LoggingConfig -from autogpt.plugins.plugins_config import PluginsConfig from autogpt.speech import TTSConfig logger = logging.getLogger(__name__) @@ -33,7 +31,6 @@ PROJECT_ROOT = Path(autogpt.__file__).parent.parent AI_SETTINGS_FILE = Path("ai_settings.yaml") AZURE_CONFIG_FILE = Path("azure.yaml") -PLUGINS_CONFIG_FILE = Path("plugins_config.yaml") PROMPT_SETTINGS_FILE = Path("prompt_settings.yaml") GPT_4_MODEL = OpenAIModelName.GPT4 @@ -54,9 +51,6 @@ class Config(SystemSettings, arbitrary_types_allowed=True): authorise_key: str = UserConfigurable(default="y", from_env="AUTHORISE_COMMAND_KEY") exit_key: str = UserConfigurable(default="n", from_env="EXIT_KEY") noninteractive_mode: bool = False - chat_messages_enabled: bool = UserConfigurable( - default=True, from_env=lambda: os.getenv("CHAT_MESSAGES_ENABLED") == "True" - ) # TTS configuration logging: LoggingConfig = LoggingConfig() @@ -181,29 +175,6 @@ class Config(SystemSettings, arbitrary_types_allowed=True): from_env="USER_AGENT", ) - ################### - # Plugin Settings # - ################### - plugins_dir: str = UserConfigurable("plugins", from_env="PLUGINS_DIR") - plugins_config_file: Path = UserConfigurable( - default=PLUGINS_CONFIG_FILE, from_env="PLUGINS_CONFIG_FILE" - ) - plugins_config: PluginsConfig = Field( - default_factory=lambda: PluginsConfig(plugins={}) - ) - plugins: list[AutoGPTPluginTemplate] = Field(default_factory=list, exclude=True) - plugins_allowlist: list[str] = UserConfigurable( - default_factory=list, - from_env=lambda: _safe_split(os.getenv("ALLOWLISTED_PLUGINS")), - ) - plugins_denylist: list[str] = UserConfigurable( - default_factory=list, - from_env=lambda: _safe_split(os.getenv("DENYLISTED_PLUGINS")), - ) - plugins_openai: list[str] = UserConfigurable( - default_factory=list, from_env=lambda: _safe_split(os.getenv("OPENAI_PLUGINS")) - ) - ############### # Credentials # ############### @@ -231,16 +202,6 @@ class Config(SystemSettings, arbitrary_types_allowed=True): # Stable Diffusion sd_webui_auth: Optional[str] = UserConfigurable(from_env="SD_WEBUI_AUTH") - @validator("plugins", each_item=True) - def validate_plugins(cls, p: AutoGPTPluginTemplate | Any): - assert issubclass( - p.__class__, AutoGPTPluginTemplate - ), f"{p} does not subclass AutoGPTPluginTemplate" - assert ( - p.__class__.__name__ != "AutoGPTPluginTemplate" - ), f"Plugins must subclass AutoGPTPluginTemplate; {p} is a template instance" - return p - @validator("openai_functions") def validate_openai_functions(cls, v: bool, values: dict[str, Any]): if v: @@ -266,7 +227,6 @@ def build_config_from_env(cls, project_root: Path = PROJECT_ROOT) -> Config: for k in { "ai_settings_file", # TODO: deprecate or repurpose "prompt_settings_file", # TODO: deprecate or repurpose - "plugins_config_file", # TODO: move from project root "azure_config_file", # TODO: move from project root }: setattr(config, k, project_root / getattr(config, k)) @@ -278,12 +238,6 @@ def build_config_from_env(cls, project_root: Path = PROJECT_ROOT) -> Config: ): config.openai_credentials.load_azure_config(config_file) - config.plugins_config = PluginsConfig.load_config( - config.plugins_config_file, - config.plugins_denylist, - config.plugins_allowlist, - ) - return config diff --git a/autogpts/autogpt/autogpt/logs/__init__.py b/autogpts/autogpt/autogpt/logs/__init__.py index dc99649e506..f48d5a6f150 100644 --- a/autogpts/autogpt/autogpt/logs/__init__.py +++ b/autogpts/autogpt/autogpt/logs/__init__.py @@ -1,4 +1,4 @@ -from .config import configure_chat_plugins, configure_logging +from .config import configure_logging from .helpers import user_friendly_output from .log_cycle import ( CURRENT_CONTEXT_FILE_NAME, @@ -13,7 +13,6 @@ __all__ = [ "configure_logging", - "configure_chat_plugins", "user_friendly_output", "CURRENT_CONTEXT_FILE_NAME", "NEXT_ACTION_FILE_NAME", diff --git a/autogpts/autogpt/autogpt/logs/config.py b/autogpts/autogpt/autogpt/logs/config.py index 3b6860e8fb2..3569933a984 100644 --- a/autogpts/autogpt/autogpt/logs/config.py +++ b/autogpts/autogpt/autogpt/logs/config.py @@ -8,11 +8,9 @@ from pathlib import Path from typing import TYPE_CHECKING, Optional -from auto_gpt_plugin_template import AutoGPTPluginTemplate from openai._base_client import log as openai_logger if TYPE_CHECKING: - from autogpt.config import Config from autogpt.speech import TTSConfig from autogpt.core.configuration import SystemConfiguration, UserConfigurable @@ -34,8 +32,6 @@ SPEECH_OUTPUT_LOGGER = "VOICE" USER_FRIENDLY_OUTPUT_LOGGER = "USER_FRIENDLY_OUTPUT" -_chat_plugins: list[AutoGPTPluginTemplate] = [] - class LogFormatName(str, enum.Enum): SIMPLE = "simple" @@ -222,19 +218,3 @@ def configure_logging( # Disable debug logging from OpenAI library openai_logger.setLevel(logging.WARNING) - - -def configure_chat_plugins(config: Config) -> None: - """Configure chat plugins for use by the logging module""" - - logger = logging.getLogger(__name__) - - # Add chat plugins capable of report to logger - if config.chat_messages_enabled: - if _chat_plugins: - _chat_plugins.clear() - - for plugin in config.plugins: - if hasattr(plugin, "can_handle_report") and plugin.can_handle_report(): - logger.debug(f"Loaded plugin into logger: {plugin.__class__.__name__}") - _chat_plugins.append(plugin) diff --git a/autogpts/autogpt/autogpt/logs/helpers.py b/autogpts/autogpt/autogpt/logs/helpers.py index 580e09a8ae0..d81f01d6722 100644 --- a/autogpts/autogpt/autogpt/logs/helpers.py +++ b/autogpts/autogpt/autogpt/logs/helpers.py @@ -3,7 +3,7 @@ from colorama import Fore -from .config import SPEECH_OUTPUT_LOGGER, USER_FRIENDLY_OUTPUT_LOGGER, _chat_plugins +from .config import SPEECH_OUTPUT_LOGGER, USER_FRIENDLY_OUTPUT_LOGGER def user_friendly_output( @@ -21,10 +21,6 @@ def user_friendly_output( """ logger = logging.getLogger(USER_FRIENDLY_OUTPUT_LOGGER) - if _chat_plugins: - for plugin in _chat_plugins: - plugin.report(f"{title}: {message}") - logger.log( level, message, diff --git a/autogpts/autogpt/autogpt/memory/vector/utils.py b/autogpts/autogpt/autogpt/memory/vector/utils.py index b8b87a49133..e201b738e22 100644 --- a/autogpts/autogpt/autogpt/memory/vector/utils.py +++ b/autogpts/autogpt/autogpt/memory/vector/utils.py @@ -1,5 +1,4 @@ import logging -from contextlib import suppress from typing import Any, Sequence, overload import numpy as np @@ -51,16 +50,9 @@ async def get_embedding( if isinstance(input, str): input = input.replace("\n", " ") - - with suppress(NotImplementedError): - return _get_embedding_with_plugin(input, config) - elif multiple and isinstance(input[0], str): input = [text.replace("\n", " ") for text in input] - with suppress(NotImplementedError): - return [_get_embedding_with_plugin(i, config) for i in input] - model = config.embedding_model logger.debug( @@ -86,13 +78,3 @@ async def get_embedding( ) embeddings.append(result.embedding) return embeddings - - -def _get_embedding_with_plugin(text: str, config: Config) -> Embedding: - for plugin in config.plugins: - if plugin.can_handle_text_embedding(text): - embedding = plugin.handle_text_embedding(text) - if embedding is not None: - return embedding - - raise NotImplementedError diff --git a/autogpts/autogpt/autogpt/models/base_open_ai_plugin.py b/autogpts/autogpt/autogpt/models/base_open_ai_plugin.py deleted file mode 100644 index a269bb9c415..00000000000 --- a/autogpts/autogpt/autogpt/models/base_open_ai_plugin.py +++ /dev/null @@ -1,251 +0,0 @@ -"""Handles loading of plugins.""" -from typing import Any, Dict, List, Optional, Tuple, TypedDict, TypeVar - -from auto_gpt_plugin_template import AutoGPTPluginTemplate - -PromptGenerator = TypeVar("PromptGenerator") - - -class Message(TypedDict): - role: str - content: str - - -class BaseOpenAIPlugin(AutoGPTPluginTemplate): - """ - This is a BaseOpenAIPlugin class for generating AutoGPT plugins. - """ - - def __init__(self, manifests_specs_clients: dict): - # super().__init__() - self._name = manifests_specs_clients["manifest"]["name_for_model"] - self._version = manifests_specs_clients["manifest"]["schema_version"] - self._description = manifests_specs_clients["manifest"]["description_for_model"] - self._client = manifests_specs_clients["client"] - self._manifest = manifests_specs_clients["manifest"] - self._openapi_spec = manifests_specs_clients["openapi_spec"] - - def can_handle_on_response(self) -> bool: - """This method is called to check that the plugin can - handle the on_response method. - Returns: - bool: True if the plugin can handle the on_response method.""" - return False - - def on_response(self, response: str, *args, **kwargs) -> str: - """This method is called when a response is received from the model.""" - return response - - def can_handle_post_prompt(self) -> bool: - """This method is called to check that the plugin can - handle the post_prompt method. - Returns: - bool: True if the plugin can handle the post_prompt method.""" - return False - - def post_prompt(self, prompt: PromptGenerator) -> PromptGenerator: - """This method is called just after the generate_prompt is called, - but actually before the prompt is generated. - Args: - prompt (PromptGenerator): The prompt generator. - Returns: - PromptGenerator: The prompt generator. - """ - return prompt - - def can_handle_on_planning(self) -> bool: - """This method is called to check that the plugin can - handle the on_planning method. - Returns: - bool: True if the plugin can handle the on_planning method.""" - return False - - def on_planning( - self, prompt: PromptGenerator, messages: List[Message] - ) -> Optional[str]: - """This method is called before the planning chat completion is done. - Args: - prompt (PromptGenerator): The prompt generator. - messages (List[str]): The list of messages. - """ - - def can_handle_post_planning(self) -> bool: - """This method is called to check that the plugin can - handle the post_planning method. - Returns: - bool: True if the plugin can handle the post_planning method.""" - return False - - def post_planning(self, response: str) -> str: - """This method is called after the planning chat completion is done. - Args: - response (str): The response. - Returns: - str: The resulting response. - """ - return response - - def can_handle_pre_instruction(self) -> bool: - """This method is called to check that the plugin can - handle the pre_instruction method. - Returns: - bool: True if the plugin can handle the pre_instruction method.""" - return False - - def pre_instruction(self, messages: List[Message]) -> List[Message]: - """This method is called before the instruction chat is done. - Args: - messages (List[Message]): The list of context messages. - Returns: - List[Message]: The resulting list of messages. - """ - return messages - - def can_handle_on_instruction(self) -> bool: - """This method is called to check that the plugin can - handle the on_instruction method. - Returns: - bool: True if the plugin can handle the on_instruction method.""" - return False - - def on_instruction(self, messages: List[Message]) -> Optional[str]: - """This method is called when the instruction chat is done. - Args: - messages (List[Message]): The list of context messages. - Returns: - Optional[str]: The resulting message. - """ - - def can_handle_post_instruction(self) -> bool: - """This method is called to check that the plugin can - handle the post_instruction method. - Returns: - bool: True if the plugin can handle the post_instruction method.""" - return False - - def post_instruction(self, response: str) -> str: - """This method is called after the instruction chat is done. - Args: - response (str): The response. - Returns: - str: The resulting response. - """ - return response - - def can_handle_pre_command(self) -> bool: - """This method is called to check that the plugin can - handle the pre_command method. - Returns: - bool: True if the plugin can handle the pre_command method.""" - return False - - def pre_command( - self, command_name: str, arguments: Dict[str, Any] - ) -> Tuple[str, Dict[str, Any]]: - """This method is called before the command is executed. - Args: - command_name (str): The command name. - arguments (Dict[str, Any]): The arguments. - Returns: - Tuple[str, Dict[str, Any]]: The command name and the arguments. - """ - return command_name, arguments - - def can_handle_post_command(self) -> bool: - """This method is called to check that the plugin can - handle the post_command method. - Returns: - bool: True if the plugin can handle the post_command method.""" - return False - - def post_command(self, command_name: str, response: str) -> str: - """This method is called after the command is executed. - Args: - command_name (str): The command name. - response (str): The response. - Returns: - str: The resulting response. - """ - return response - - def can_handle_chat_completion( - self, messages: Dict[Any, Any], model: str, temperature: float, max_tokens: int - ) -> bool: - """This method is called to check that the plugin can - handle the chat_completion method. - Args: - messages (List[Message]): The messages. - model (str): The model name. - temperature (float): The temperature. - max_tokens (int): The max tokens. - Returns: - bool: True if the plugin can handle the chat_completion method.""" - return False - - def handle_chat_completion( - self, messages: List[Message], model: str, temperature: float, max_tokens: int - ) -> str: - """This method is called when the chat completion is done. - Args: - messages (List[Message]): The messages. - model (str): The model name. - temperature (float): The temperature. - max_tokens (int): The max tokens. - Returns: - str: The resulting response. - """ - - def can_handle_text_embedding(self, text: str) -> bool: - """This method is called to check that the plugin can - handle the text_embedding method. - - Args: - text (str): The text to be convert to embedding. - Returns: - bool: True if the plugin can handle the text_embedding method.""" - return False - - def handle_text_embedding(self, text: str) -> list[float]: - """This method is called to create a text embedding. - - Args: - text (str): The text to be convert to embedding. - Returns: - list[float]: The created embedding vector. - """ - - def can_handle_user_input(self, user_input: str) -> bool: - """This method is called to check that the plugin can - handle the user_input method. - - Args: - user_input (str): The user input. - - Returns: - bool: True if the plugin can handle the user_input method.""" - return False - - def user_input(self, user_input: str) -> str: - """This method is called to request user input to the user. - - Args: - user_input (str): The question or prompt to ask the user. - - Returns: - str: The user input. - """ - - def can_handle_report(self) -> bool: - """This method is called to check that the plugin can - handle the report method. - - Returns: - bool: True if the plugin can handle the report method.""" - return False - - def report(self, message: str) -> None: - """This method is called to report a message to the user. - - Args: - message (str): The message to report. - """ diff --git a/autogpts/autogpt/autogpt/plugins/__init__.py b/autogpts/autogpt/autogpt/plugins/__init__.py deleted file mode 100644 index 618a9895ab9..00000000000 --- a/autogpts/autogpt/autogpt/plugins/__init__.py +++ /dev/null @@ -1,330 +0,0 @@ -"""Handles loading of plugins.""" -from __future__ import annotations - -import importlib.util -import inspect -import json -import logging -import os -import zipfile -from pathlib import Path -from typing import TYPE_CHECKING, List -from urllib.parse import urlparse -from zipimport import ZipImportError, zipimporter - -import openapi_python_client -import requests -from auto_gpt_plugin_template import AutoGPTPluginTemplate -from openapi_python_client.config import Config as OpenAPIConfig - -if TYPE_CHECKING: - from autogpt.config import Config - -from autogpt.models.base_open_ai_plugin import BaseOpenAIPlugin - -logger = logging.getLogger(__name__) - - -def inspect_zip_for_modules(zip_path: str) -> list[str]: - """ - Inspect a zipfile for a modules. - - Args: - zip_path (str): Path to the zipfile. - debug (bool, optional): Enable debug logging. Defaults to False. - - Returns: - list[str]: The list of module names found or empty list if none were found. - """ - result = [] - with zipfile.ZipFile(zip_path, "r") as zfile: - for name in zfile.namelist(): - if name.endswith("__init__.py") and not name.startswith("__MACOSX"): - logger.debug(f"Found module '{name}' in the zipfile at: {name}") - result.append(name) - if len(result) == 0: - logger.debug(f"Module '__init__.py' not found in the zipfile @ {zip_path}.") - return result - - -def write_dict_to_json_file(data: dict, file_path: str) -> None: - """ - Write a dictionary to a JSON file. - Args: - data (dict): Dictionary to write. - file_path (str): Path to the file. - """ - with open(file_path, "w") as file: - json.dump(data, file, indent=4) - - -def fetch_openai_plugins_manifest_and_spec(config: Config) -> dict: - """ - Fetch the manifest for a list of OpenAI plugins. - Args: - urls (List): List of URLs to fetch. - Returns: - dict: per url dictionary of manifest and spec. - """ - # TODO add directory scan - manifests = {} - for url in config.plugins_openai: - openai_plugin_client_dir = f"{config.plugins_dir}/openai/{urlparse(url).netloc}" - create_directory_if_not_exists(openai_plugin_client_dir) - if not os.path.exists(f"{openai_plugin_client_dir}/ai-plugin.json"): - try: - response = requests.get(f"{url}/.well-known/ai-plugin.json") - if response.status_code == 200: - manifest = response.json() - if manifest["schema_version"] != "v1": - logger.warning( - "Unsupported manifest version: " - f"{manifest['schem_version']} for {url}" - ) - continue - if manifest["api"]["type"] != "openapi": - logger.warning( - f"Unsupported API type: {manifest['api']['type']} for {url}" - ) - continue - write_dict_to_json_file( - manifest, f"{openai_plugin_client_dir}/ai-plugin.json" - ) - else: - logger.warning( - f"Failed to fetch manifest for {url}: {response.status_code}" - ) - except requests.exceptions.RequestException as e: - logger.warning(f"Error while requesting manifest from {url}: {e}") - else: - logger.info(f"Manifest for {url} already exists") - manifest = json.load(open(f"{openai_plugin_client_dir}/ai-plugin.json")) - if not os.path.exists(f"{openai_plugin_client_dir}/openapi.json"): - openapi_spec = openapi_python_client._get_document( - url=manifest["api"]["url"], path=None, timeout=5 - ) - write_dict_to_json_file( - openapi_spec, f"{openai_plugin_client_dir}/openapi.json" - ) - else: - logger.info(f"OpenAPI spec for {url} already exists") - openapi_spec = json.load(open(f"{openai_plugin_client_dir}/openapi.json")) - manifests[url] = {"manifest": manifest, "openapi_spec": openapi_spec} - return manifests - - -def create_directory_if_not_exists(directory_path: str) -> bool: - """ - Create a directory if it does not exist. - Args: - directory_path (str): Path to the directory. - Returns: - bool: True if the directory was created, else False. - """ - if not os.path.exists(directory_path): - try: - os.makedirs(directory_path) - logger.debug(f"Created directory: {directory_path}") - return True - except OSError as e: - logger.warning(f"Error creating directory {directory_path}: {e}") - return False - else: - logger.info(f"Directory {directory_path} already exists") - return True - - -def initialize_openai_plugins(manifests_specs: dict, config: Config) -> dict: - """ - Initialize OpenAI plugins. - Args: - manifests_specs (dict): per url dictionary of manifest and spec. - config (Config): Config instance including plugins config - debug (bool, optional): Enable debug logging. Defaults to False. - Returns: - dict: per url dictionary of manifest, spec and client. - """ - openai_plugins_dir = f"{config.plugins_dir}/openai" - if create_directory_if_not_exists(openai_plugins_dir): - for url, manifest_spec in manifests_specs.items(): - openai_plugin_client_dir = f"{openai_plugins_dir}/{urlparse(url).hostname}" - _meta_option = (openapi_python_client.MetaType.SETUP,) - _config = OpenAPIConfig( - **{ - "project_name_override": "client", - "package_name_override": "client", - } - ) - prev_cwd = Path.cwd() - os.chdir(openai_plugin_client_dir) - - if not os.path.exists("client"): - client_results = openapi_python_client.create_new_client( - url=manifest_spec["manifest"]["api"]["url"], - path=None, - meta=_meta_option, - config=_config, - ) - if client_results: - logger.warning( - f"Error creating OpenAPI client: {client_results[0].header} \n" - f" details: {client_results[0].detail}" - ) - continue - spec = importlib.util.spec_from_file_location( - "client", "client/client/client.py" - ) - module = importlib.util.module_from_spec(spec) - - try: - spec.loader.exec_module(module) - finally: - os.chdir(prev_cwd) - - client = module.Client(base_url=url) - manifest_spec["client"] = client - return manifests_specs - - -def instantiate_openai_plugin_clients(manifests_specs_clients: dict) -> dict: - """ - Instantiates BaseOpenAIPlugin instances for each OpenAI plugin. - Args: - manifests_specs_clients (dict): per url dictionary of manifest, spec and client. - config (Config): Config instance including plugins config - debug (bool, optional): Enable debug logging. Defaults to False. - Returns: - plugins (dict): per url dictionary of BaseOpenAIPlugin instances. - - """ - plugins = {} - for url, manifest_spec_client in manifests_specs_clients.items(): - plugins[url] = BaseOpenAIPlugin(manifest_spec_client) - return plugins - - -def scan_plugins(config: Config) -> List[AutoGPTPluginTemplate]: - """Scan the plugins directory for plugins and loads them. - - Args: - config (Config): Config instance including plugins config - debug (bool, optional): Enable debug logging. Defaults to False. - - Returns: - List[Tuple[str, Path]]: List of plugins. - """ - loaded_plugins = [] - # Generic plugins - plugins_path = Path(config.plugins_dir) - - plugins_config = config.plugins_config - # Directory-based plugins - for plugin_path in [f for f in Path(config.plugins_dir).iterdir() if f.is_dir()]: - # Avoid going into __pycache__ or other hidden directories - if plugin_path.name.startswith("__"): - continue - - plugin_module_name = plugin_path.name - qualified_module_name = ".".join(plugin_path.parts) - - try: - plugin = importlib.import_module(qualified_module_name) - except ImportError as e: - logger.error( - f"Failed to load {qualified_module_name} from {plugin_path}: {e}" - ) - continue - - if not plugins_config.is_enabled(plugin_module_name): - logger.warning( - f"Plugin folder {plugin_module_name} found but not configured. " - "If this is a legitimate plugin, please add it to plugins_config.yaml " - f"(key: {plugin_module_name})." - ) - continue - - for _, class_obj in inspect.getmembers(plugin): - if ( - hasattr(class_obj, "_abc_impl") - and AutoGPTPluginTemplate in class_obj.__bases__ - ): - loaded_plugins.append(class_obj()) - - # Zip-based plugins - for plugin in plugins_path.glob("*.zip"): - if moduleList := inspect_zip_for_modules(str(plugin)): - for module in moduleList: - plugin = Path(plugin) - module = Path(module) - logger.debug(f"Zipped Plugin: {plugin}, Module: {module}") - zipped_package = zipimporter(str(plugin)) - try: - zipped_module = zipped_package.load_module(str(module.parent)) - except ZipImportError as e: - logger.error(f"Failed to load {module.parent} from {plugin}: {e}") - continue - - for key in dir(zipped_module): - if key.startswith("__"): - continue - - a_module = getattr(zipped_module, key) - if not inspect.isclass(a_module): - continue - - if ( - issubclass(a_module, AutoGPTPluginTemplate) - and a_module.__name__ != "AutoGPTPluginTemplate" - ): - plugin_name = a_module.__name__ - plugin_configured = plugins_config.get(plugin_name) is not None - plugin_enabled = plugins_config.is_enabled(plugin_name) - - if plugin_configured and plugin_enabled: - logger.debug( - f"Loading plugin {plugin_name}. " - "Enabled in plugins_config.yaml." - ) - loaded_plugins.append(a_module()) - elif plugin_configured and not plugin_enabled: - logger.debug( - f"Not loading plugin {plugin_name}. " - "Disabled in plugins_config.yaml." - ) - elif not plugin_configured: - logger.warning( - f"Not loading plugin {plugin_name}. " - f"No entry for '{plugin_name}' in plugins_config.yaml. " - "Note: Zipped plugins should use the class name " - f"({plugin_name}) as the key." - ) - else: - if ( - module_name := getattr(a_module, "__name__", str(a_module)) - ) != "AutoGPTPluginTemplate": - logger.debug( - f"Skipping '{module_name}' because it doesn't subclass " - "AutoGPTPluginTemplate." - ) - - # OpenAI plugins - if config.plugins_openai: - manifests_specs = fetch_openai_plugins_manifest_and_spec(config) - if manifests_specs.keys(): - manifests_specs_clients = initialize_openai_plugins(manifests_specs, config) - for url, openai_plugin_meta in manifests_specs_clients.items(): - if not plugins_config.is_enabled(url): - plugin_name = openai_plugin_meta["manifest"]["name_for_model"] - logger.warning( - f"OpenAI Plugin {plugin_name} found but not configured" - ) - continue - - plugin = BaseOpenAIPlugin(openai_plugin_meta) - loaded_plugins.append(plugin) - - if loaded_plugins: - logger.info(f"\nPlugins found: {len(loaded_plugins)}\n" "--------------------") - for plugin in loaded_plugins: - logger.info(f"{plugin._name}: {plugin._version} - {plugin._description}") - return loaded_plugins diff --git a/autogpts/autogpt/autogpt/plugins/plugin_config.py b/autogpts/autogpt/autogpt/plugins/plugin_config.py deleted file mode 100644 index bdf77d832fd..00000000000 --- a/autogpts/autogpt/autogpt/plugins/plugin_config.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Any - -from pydantic import BaseModel - - -class PluginConfig(BaseModel): - """Class for holding configuration of a single plugin""" - - name: str - enabled: bool = False - config: dict[str, Any] = None diff --git a/autogpts/autogpt/autogpt/plugins/plugins_config.py b/autogpts/autogpt/autogpt/plugins/plugins_config.py deleted file mode 100644 index ad96d4a378d..00000000000 --- a/autogpts/autogpt/autogpt/plugins/plugins_config.py +++ /dev/null @@ -1,118 +0,0 @@ -from __future__ import annotations - -import logging -from pathlib import Path -from typing import Union - -import yaml -from pydantic import BaseModel - -from autogpt.plugins.plugin_config import PluginConfig - -logger = logging.getLogger(__name__) - - -class PluginsConfig(BaseModel): - """Class for holding configuration of all plugins""" - - plugins: dict[str, PluginConfig] - - def __repr__(self): - return f"PluginsConfig({self.plugins})" - - def get(self, name: str) -> Union[PluginConfig, None]: - return self.plugins.get(name) - - def is_enabled(self, name) -> bool: - plugin_config = self.plugins.get(name) - return plugin_config is not None and plugin_config.enabled - - @classmethod - def load_config( - cls, - plugins_config_file: Path, - plugins_denylist: list[str], - plugins_allowlist: list[str], - ) -> "PluginsConfig": - empty_config = cls(plugins={}) - - try: - config_data = cls.deserialize_config_file( - plugins_config_file, - plugins_denylist, - plugins_allowlist, - ) - if type(config_data) is not dict: - logger.error( - f"Expected plugins config to be a dict, got {type(config_data)}." - " Continuing without plugins." - ) - return empty_config - return cls(plugins=config_data) - - except BaseException as e: - logger.error( - f"Plugin config is invalid. Continuing without plugins. Error: {e}" - ) - return empty_config - - @classmethod - def deserialize_config_file( - cls, - plugins_config_file: Path, - plugins_denylist: list[str], - plugins_allowlist: list[str], - ) -> dict[str, PluginConfig]: - if not plugins_config_file.is_file(): - logger.warning("plugins_config.yaml does not exist, creating base config.") - cls.create_empty_plugins_config( - plugins_config_file, - plugins_denylist, - plugins_allowlist, - ) - - with open(plugins_config_file, "r") as f: - plugins_config = yaml.load(f, Loader=yaml.SafeLoader) - - plugins = {} - for name, plugin in plugins_config.items(): - if type(plugin) is dict: - plugins[name] = PluginConfig( - name=name, - enabled=plugin.get("enabled", False), - config=plugin.get("config", {}), - ) - elif isinstance(plugin, PluginConfig): - plugins[name] = plugin - else: - raise ValueError(f"Invalid plugin config data type: {type(plugin)}") - return plugins - - @staticmethod - def create_empty_plugins_config( - plugins_config_file: Path, - plugins_denylist: list[str], - plugins_allowlist: list[str], - ): - """ - Create an empty plugins_config.yaml file. - Fill it with values from old env variables. - """ - base_config = {} - - logger.debug(f"Legacy plugin denylist: {plugins_denylist}") - logger.debug(f"Legacy plugin allowlist: {plugins_allowlist}") - - # Backwards-compatibility shim - for plugin_name in plugins_denylist: - base_config[plugin_name] = {"enabled": False, "config": {}} - - for plugin_name in plugins_allowlist: - base_config[plugin_name] = {"enabled": True, "config": {}} - - logger.debug(f"Constructed base plugins config: {base_config}") - - logger.debug(f"Creating plugin config file {plugins_config_file}") - with open(plugins_config_file, "w+") as f: - f.write(yaml.dump(base_config)) - return base_config diff --git a/autogpts/autogpt/poetry.lock b/autogpts/autogpt/poetry.lock index 21a6c382b09..df135230dab 100644 --- a/autogpts/autogpt/poetry.lock +++ b/autogpts/autogpt/poetry.lock @@ -1,16 +1,5 @@ # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. -[[package]] -name = "abstract-singleton" -version = "1.0.1" -description = "An abstract singleton class." -optional = false -python-versions = ">=3.8" -files = [ - {file = "abstract_singleton-1.0.1-py3-none-any.whl", hash = "sha256:1f5e2359a609360bc08d975f578cce75a752df06db561efb679e69646199ec1d"}, - {file = "abstract_singleton-1.0.1.tar.gz", hash = "sha256:d97d26ecbcb7422f78df1b0bca48a03df5ba04cf58844c6da033a7840beaae82"}, -] - [[package]] name = "agbenchmark" version = "0.0.10" @@ -276,24 +265,6 @@ tests = ["attrs[tests-no-zope]", "zope-interface"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] -[[package]] -name = "auto_gpt_plugin_template" -version = "0.0.2" -description = "The template plugin for Auto-GPT." -optional = false -python-versions = ">=3.8" -files = [] -develop = false - -[package.dependencies] -abstract-singleton = "*" - -[package.source] -type = "git" -url = "https://github.com/Significant-Gravitas/Auto-GPT-Plugin-Template" -reference = "0.1.0" -resolved_reference = "7612a14c629dc64ad870eee4d05850d60e1dd9ce" - [[package]] name = "autoflake" version = "2.2.1" @@ -338,13 +309,13 @@ uvicorn = "^0.23.2" webdriver-manager = "^4.0.1" [package.extras] -benchmark = ["agbenchmark @ git+https://github.com/Significant-Gravitas/AutoGPT.git#subdirectory=benchmark"] +benchmark = ["agbenchmark @ file:///Users/czerwinski/Library/Caches/pypoetry/virtualenvs/agpt-JtDOdZb2-py3.11/src/AutoGPT/benchmark"] [package.source] type = "git" url = "https://github.com/Significant-Gravitas/AutoGPT.git" -reference = "ab05b7ae70754c063909" -resolved_reference = "ab05b7ae70754c06390982d237d86dc7290cd1aa" +reference = "HEAD" +resolved_reference = "fd3f8fa5fc86271e4e319258fefdb3065d1aa0d4" subdirectory = "autogpts/forge" [[package]] @@ -7263,4 +7234,4 @@ benchmark = ["agbenchmark"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "afa9674e032573e483e977e818766efe18ea4f52efa1ce6dfc71686772371b5b" +content-hash = "e6eab5c079d53f075ce701e86a2007e7ebeb635ac067d25f555bfea363bcc630" diff --git a/autogpts/autogpt/pyproject.toml b/autogpts/autogpt/pyproject.toml index 404bffaaa5f..e1b0c32f670 100644 --- a/autogpts/autogpt/pyproject.toml +++ b/autogpts/autogpt/pyproject.toml @@ -22,9 +22,8 @@ serve = "autogpt.app.cli:serve" [tool.poetry.dependencies] python = "^3.10" -auto-gpt-plugin-template = {git = "https://github.com/Significant-Gravitas/Auto-GPT-Plugin-Template", rev = "0.1.0"} # autogpt-forge = { path = "../forge" } -autogpt-forge = {git = "https://github.com/Significant-Gravitas/AutoGPT.git", rev = "ab05b7ae70754c063909", subdirectory = "autogpts/forge"} +autogpt-forge = {git = "https://github.com/Significant-Gravitas/AutoGPT.git", subdirectory = "autogpts/forge"} beautifulsoup4 = "^4.12.2" boto3 = "^1.33.6" charset-normalizer = "^3.1.0" diff --git a/autogpts/autogpt/scripts/install_plugin_deps.py b/autogpts/autogpt/scripts/install_plugin_deps.py deleted file mode 100644 index 02cbfc0be92..00000000000 --- a/autogpts/autogpt/scripts/install_plugin_deps.py +++ /dev/null @@ -1,66 +0,0 @@ -import logging -import os -import subprocess -import sys -import zipfile -from glob import glob -from pathlib import Path - -logger = logging.getLogger(__name__) - - -def install_plugin_dependencies(): - """ - Installs dependencies for all plugins in the plugins dir. - - Args: - None - - Returns: - None - """ - plugins_dir = Path(os.getenv("PLUGINS_DIR", "plugins")) - - logger.debug("Checking for dependencies in zipped plugins...") - - # Install zip-based plugins - for plugin_archive in plugins_dir.glob("*.zip"): - logger.debug(f"Checking for requirements in '{plugin_archive}'...") - with zipfile.ZipFile(str(plugin_archive), "r") as zfile: - if not zfile.namelist(): - continue - - # Assume the first entry in the list will be (in) the lowest common dir - first_entry = zfile.namelist()[0] - basedir = first_entry.rsplit("/", 1)[0] if "/" in first_entry else "" - logger.debug(f"Looking for requirements.txt in '{basedir}'") - - basereqs = os.path.join(basedir, "requirements.txt") - try: - extracted = zfile.extract(basereqs, path=plugins_dir) - except KeyError as e: - logger.debug(e.args[0]) - continue - - logger.debug(f"Installing dependencies from '{basereqs}'...") - subprocess.check_call( - [sys.executable, "-m", "pip", "install", "-r", extracted] - ) - os.remove(extracted) - os.rmdir(os.path.join(plugins_dir, basedir)) - - logger.debug("Checking for dependencies in other plugin folders...") - - # Install directory-based plugins - for requirements_file in glob(f"{plugins_dir}/*/requirements.txt"): - logger.debug(f"Installing dependencies from '{requirements_file}'...") - subprocess.check_call( - [sys.executable, "-m", "pip", "install", "-r", requirements_file], - stdout=subprocess.DEVNULL, - ) - - logger.debug("Finished installing plugin dependencies") - - -if __name__ == "__main__": - install_plugin_dependencies() diff --git a/autogpts/autogpt/tests/conftest.py b/autogpts/autogpt/tests/conftest.py index b59b4c4c00e..29479f6f01a 100644 --- a/autogpts/autogpt/tests/conftest.py +++ b/autogpts/autogpt/tests/conftest.py @@ -3,10 +3,8 @@ import os import uuid from pathlib import Path -from tempfile import TemporaryDirectory import pytest -import yaml from pytest_mock import MockerFixture from autogpt.agents.agent import Agent, AgentConfiguration, AgentSettings @@ -48,23 +46,8 @@ def storage(app_data_dir: Path) -> FileStorage: return storage -@pytest.fixture -def temp_plugins_config_file(): - """ - Create a plugins_config.yaml file in a temp directory - so that it doesn't mess with existing ones. - """ - config_directory = TemporaryDirectory() - config_file = Path(config_directory.name) / "plugins_config.yaml" - with open(config_file, "w+") as f: - f.write(yaml.dump({})) - - yield config_file - - @pytest.fixture(scope="function") def config( - temp_plugins_config_file: Path, tmp_project_root: Path, app_data_dir: Path, mocker: MockerFixture, @@ -75,19 +58,8 @@ def config( config.app_data_dir = app_data_dir - config.plugins_dir = "tests/unit/data/test_plugins" - config.plugins_config_file = temp_plugins_config_file - config.noninteractive_mode = True - # avoid circular dependency - from autogpt.plugins.plugins_config import PluginsConfig - - config.plugins_config = PluginsConfig.load_config( - plugins_config_file=config.plugins_config_file, - plugins_denylist=config.plugins_denylist, - plugins_allowlist=config.plugins_allowlist, - ) yield config @@ -125,7 +97,6 @@ def agent( smart_llm=config.smart_llm, allow_fs_access=not config.restrict_to_workspace, use_functions_api=config.openai_functions, - plugins=config.plugins, ), history=Agent.default_settings.history.copy(deep=True), ) diff --git a/autogpts/autogpt/tests/integration/agent_factory.py b/autogpts/autogpt/tests/integration/agent_factory.py index 59b3164aa0e..b51759f85ce 100644 --- a/autogpts/autogpt/tests/integration/agent_factory.py +++ b/autogpts/autogpt/tests/integration/agent_factory.py @@ -41,7 +41,6 @@ def dummy_agent(config: Config, llm_provider, memory_json_file): fast_llm=config.fast_llm, smart_llm=config.smart_llm, use_functions_api=config.openai_functions, - plugins=config.plugins, ), prompt_config=agent_prompt_config, history=Agent.default_settings.history.copy(deep=True), diff --git a/autogpts/autogpt/tests/unit/data/test_plugins/Auto-GPT-Plugin-Test-master.zip b/autogpts/autogpt/tests/unit/data/test_plugins/Auto-GPT-Plugin-Test-master.zip deleted file mode 100644 index 45b515adc18a6bfb9cb6700668bd3718de3f3cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15385 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 diff --git a/autogpts/autogpt/tests/unit/data/test_plugins/auto_gpt_guanaco/__init__.py b/autogpts/autogpt/tests/unit/data/test_plugins/auto_gpt_guanaco/__init__.py deleted file mode 100644 index eb024b37c07..00000000000 --- a/autogpts/autogpt/tests/unit/data/test_plugins/auto_gpt_guanaco/__init__.py +++ /dev/null @@ -1,274 +0,0 @@ -"""This is the Test plugin for AutoGPT.""" -from typing import Any, Dict, List, Optional, Tuple, TypeVar - -from auto_gpt_plugin_template import AutoGPTPluginTemplate - -PromptGenerator = TypeVar("PromptGenerator") - - -class AutoGPTGuanaco(AutoGPTPluginTemplate): - """ - This is plugin for AutoGPT. - """ - - def __init__(self): - super().__init__() - self._name = "AutoGPT-Guanaco" - self._version = "0.1.0" - self._description = "This is a Guanaco local model plugin." - - def can_handle_on_response(self) -> bool: - """This method is called to check that the plugin can - handle the on_response method. - - Returns: - bool: True if the plugin can handle the on_response method.""" - return False - - def on_response(self, response: str, *args, **kwargs) -> str: - """This method is called when a response is received from the model.""" - if len(response): - print("OMG OMG It's Alive!") - else: - print("Is it alive?") - - def can_handle_post_prompt(self) -> bool: - """This method is called to check that the plugin can - handle the post_prompt method. - - Returns: - bool: True if the plugin can handle the post_prompt method.""" - return False - - def post_prompt(self, prompt: PromptGenerator) -> PromptGenerator: - """This method is called just after the generate_prompt is called, - but actually before the prompt is generated. - - Args: - prompt (PromptGenerator): The prompt generator. - - Returns: - PromptGenerator: The prompt generator. - """ - - def can_handle_on_planning(self) -> bool: - """This method is called to check that the plugin can - handle the on_planning method. - - Returns: - bool: True if the plugin can handle the on_planning method.""" - return False - - def on_planning( - self, prompt: PromptGenerator, messages: List[str] - ) -> Optional[str]: - """This method is called before the planning chat completeion is done. - - Args: - prompt (PromptGenerator): The prompt generator. - messages (List[str]): The list of messages. - """ - - def can_handle_post_planning(self) -> bool: - """This method is called to check that the plugin can - handle the post_planning method. - - Returns: - bool: True if the plugin can handle the post_planning method.""" - return False - - def post_planning(self, response: str) -> str: - """This method is called after the planning chat completeion is done. - - Args: - response (str): The response. - - Returns: - str: The resulting response. - """ - - def can_handle_pre_instruction(self) -> bool: - """This method is called to check that the plugin can - handle the pre_instruction method. - - Returns: - bool: True if the plugin can handle the pre_instruction method.""" - return False - - def pre_instruction(self, messages: List[str]) -> List[str]: - """This method is called before the instruction chat is done. - - Args: - messages (List[str]): The list of context messages. - - Returns: - List[str]: The resulting list of messages. - """ - - def can_handle_on_instruction(self) -> bool: - """This method is called to check that the plugin can - handle the on_instruction method. - - Returns: - bool: True if the plugin can handle the on_instruction method.""" - return False - - def on_instruction(self, messages: List[str]) -> Optional[str]: - """This method is called when the instruction chat is done. - - Args: - messages (List[str]): The list of context messages. - - Returns: - Optional[str]: The resulting message. - """ - - def can_handle_post_instruction(self) -> bool: - """This method is called to check that the plugin can - handle the post_instruction method. - - Returns: - bool: True if the plugin can handle the post_instruction method.""" - return False - - def post_instruction(self, response: str) -> str: - """This method is called after the instruction chat is done. - - Args: - response (str): The response. - - Returns: - str: The resulting response. - """ - - def can_handle_pre_command(self) -> bool: - """This method is called to check that the plugin can - handle the pre_command method. - - Returns: - bool: True if the plugin can handle the pre_command method.""" - return False - - def pre_command( - self, command_name: str, arguments: Dict[str, Any] - ) -> Tuple[str, Dict[str, Any]]: - """This method is called before the command is executed. - - Args: - command_name (str): The command name. - arguments (Dict[str, Any]): The arguments. - - Returns: - Tuple[str, Dict[str, Any]]: The command name and the arguments. - """ - - def can_handle_post_command(self) -> bool: - """This method is called to check that the plugin can - handle the post_command method. - - Returns: - bool: True if the plugin can handle the post_command method.""" - return False - - def post_command(self, command_name: str, response: str) -> str: - """This method is called after the command is executed. - - Args: - command_name (str): The command name. - response (str): The response. - - Returns: - str: The resulting response. - """ - - def can_handle_chat_completion( - self, - messages: list[Dict[Any, Any]], - model: str, - temperature: float, - max_tokens: int, - ) -> bool: - """This method is called to check that the plugin can - handle the chat_completion method. - - Args: - messages (Dict[Any, Any]): The messages. - model (str): The model name. - temperature (float): The temperature. - max_tokens (int): The max tokens. - - Returns: - bool: True if the plugin can handle the chat_completion method.""" - return False - - def handle_chat_completion( - self, - messages: list[Dict[Any, Any]], - model: str, - temperature: float, - max_tokens: int, - ) -> str: - """This method is called when the chat completion is done. - - Args: - messages (Dict[Any, Any]): The messages. - model (str): The model name. - temperature (float): The temperature. - max_tokens (int): The max tokens. - - Returns: - str: The resulting response. - """ - - def can_handle_text_embedding(self, text: str) -> bool: - """This method is called to check that the plugin can - handle the text_embedding method. - Args: - text (str): The text to be convert to embedding. - Returns: - bool: True if the plugin can handle the text_embedding method.""" - return False - - def handle_text_embedding(self, text: str) -> list: - """This method is called when the chat completion is done. - Args: - text (str): The text to be convert to embedding. - Returns: - list: The text embedding. - """ - - def can_handle_user_input(self, user_input: str) -> bool: - """This method is called to check that the plugin can - handle the user_input method. - - Args: - user_input (str): The user input. - - Returns: - bool: True if the plugin can handle the user_input method.""" - return False - - def user_input(self, user_input: str) -> str: - """This method is called to request user input to the user. - - Args: - user_input (str): The question or prompt to ask the user. - - Returns: - str: The user input. - """ - - def can_handle_report(self) -> bool: - """This method is called to check that the plugin can - handle the report method. - - Returns: - bool: True if the plugin can handle the report method.""" - return False - - def report(self, message: str) -> None: - """This method is called to report a message to the user. - - Args: - message (str): The message to report. - """ diff --git a/autogpts/autogpt/tests/unit/models/test_base_open_api_plugin.py b/autogpts/autogpt/tests/unit/models/test_base_open_api_plugin.py deleted file mode 100644 index 7a8522e7fe5..00000000000 --- a/autogpts/autogpt/tests/unit/models/test_base_open_api_plugin.py +++ /dev/null @@ -1,81 +0,0 @@ -import pytest - -from autogpt.models.base_open_ai_plugin import BaseOpenAIPlugin - - -class DummyPlugin(BaseOpenAIPlugin): - """A dummy plugin for testing purposes.""" - - -@pytest.fixture -def dummy_plugin(): - """A dummy plugin for testing purposes.""" - manifests_specs_clients = { - "manifest": { - "name_for_model": "Dummy", - "schema_version": "1.0", - "description_for_model": "A dummy plugin for testing purposes", - }, - "client": None, - "openapi_spec": None, - } - return DummyPlugin(manifests_specs_clients) - - -def test_dummy_plugin_inheritance(dummy_plugin): - """Test that the DummyPlugin class inherits from the BaseOpenAIPlugin class.""" - assert isinstance(dummy_plugin, BaseOpenAIPlugin) - - -def test_dummy_plugin_name(dummy_plugin): - """Test that the DummyPlugin class has the correct name.""" - assert dummy_plugin._name == "Dummy" - - -def test_dummy_plugin_version(dummy_plugin): - """Test that the DummyPlugin class has the correct version.""" - assert dummy_plugin._version == "1.0" - - -def test_dummy_plugin_description(dummy_plugin): - """Test that the DummyPlugin class has the correct description.""" - assert dummy_plugin._description == "A dummy plugin for testing purposes" - - -def test_dummy_plugin_default_methods(dummy_plugin): - """Test that the DummyPlugin class has the correct default methods.""" - assert not dummy_plugin.can_handle_on_response() - assert not dummy_plugin.can_handle_post_prompt() - assert not dummy_plugin.can_handle_on_planning() - assert not dummy_plugin.can_handle_post_planning() - assert not dummy_plugin.can_handle_pre_instruction() - assert not dummy_plugin.can_handle_on_instruction() - assert not dummy_plugin.can_handle_post_instruction() - assert not dummy_plugin.can_handle_pre_command() - assert not dummy_plugin.can_handle_post_command() - assert not dummy_plugin.can_handle_chat_completion(None, None, None, None) - assert not dummy_plugin.can_handle_text_embedding(None) - - assert dummy_plugin.on_response("hello") == "hello" - assert dummy_plugin.post_prompt(None) is None - assert dummy_plugin.on_planning(None, None) is None - assert dummy_plugin.post_planning("world") == "world" - pre_instruction = dummy_plugin.pre_instruction( - [{"role": "system", "content": "Beep, bop, boop"}] - ) - assert isinstance(pre_instruction, list) - assert len(pre_instruction) == 1 - assert pre_instruction[0]["role"] == "system" - assert pre_instruction[0]["content"] == "Beep, bop, boop" - assert dummy_plugin.on_instruction(None) is None - assert dummy_plugin.post_instruction("I'm a robot") == "I'm a robot" - pre_command = dummy_plugin.pre_command("evolve", {"continuously": True}) - assert isinstance(pre_command, tuple) - assert len(pre_command) == 2 - assert pre_command[0] == "evolve" - assert pre_command[1]["continuously"] is True - post_command = dummy_plugin.post_command("evolve", "upgraded successfully!") - assert isinstance(post_command, str) - assert post_command == "upgraded successfully!" - assert dummy_plugin.handle_chat_completion(None, None, None, None) is None - assert dummy_plugin.handle_text_embedding(None) is None diff --git a/autogpts/autogpt/tests/unit/test_plugins.py b/autogpts/autogpt/tests/unit/test_plugins.py deleted file mode 100644 index f180d92bc6f..00000000000 --- a/autogpts/autogpt/tests/unit/test_plugins.py +++ /dev/null @@ -1,125 +0,0 @@ -import os - -import yaml - -from autogpt.config.config import Config -from autogpt.plugins import inspect_zip_for_modules, scan_plugins -from autogpt.plugins.plugin_config import PluginConfig -from autogpt.plugins.plugins_config import PluginsConfig - -PLUGINS_TEST_DIR = "tests/unit/data/test_plugins" -PLUGIN_TEST_ZIP_FILE = "Auto-GPT-Plugin-Test-master.zip" -PLUGIN_TEST_INIT_PY = "Auto-GPT-Plugin-Test-master/src/auto_gpt_vicuna/__init__.py" -PLUGIN_TEST_OPENAI = "https://weathergpt.vercel.app/" - - -def test_scan_plugins_openai(config: Config): - config.plugins_openai = [PLUGIN_TEST_OPENAI] - plugins_config = config.plugins_config - plugins_config.plugins[PLUGIN_TEST_OPENAI] = PluginConfig( - name=PLUGIN_TEST_OPENAI, enabled=True - ) - - # Test that the function returns the correct number of plugins - result = scan_plugins(config) - assert len(result) == 1 - - -def test_scan_plugins_generic(config: Config): - # Test that the function returns the correct number of plugins - plugins_config = config.plugins_config - plugins_config.plugins["auto_gpt_guanaco"] = PluginConfig( - name="auto_gpt_guanaco", enabled=True - ) - plugins_config.plugins["AutoGPTPVicuna"] = PluginConfig( - name="AutoGPTPVicuna", enabled=True - ) - result = scan_plugins(config) - plugin_class_names = [plugin.__class__.__name__ for plugin in result] - - assert len(result) == 2 - assert "AutoGPTGuanaco" in plugin_class_names - assert "AutoGPTPVicuna" in plugin_class_names - - -def test_scan_plugins_not_enabled(config: Config): - # Test that the function returns the correct number of plugins - plugins_config = config.plugins_config - plugins_config.plugins["auto_gpt_guanaco"] = PluginConfig( - name="auto_gpt_guanaco", enabled=True - ) - plugins_config.plugins["auto_gpt_vicuna"] = PluginConfig( - name="auto_gptp_vicuna", enabled=False - ) - result = scan_plugins(config) - plugin_class_names = [plugin.__class__.__name__ for plugin in result] - - assert len(result) == 1 - assert "AutoGPTGuanaco" in plugin_class_names - assert "AutoGPTPVicuna" not in plugin_class_names - - -def test_inspect_zip_for_modules(): - result = inspect_zip_for_modules(str(f"{PLUGINS_TEST_DIR}/{PLUGIN_TEST_ZIP_FILE}")) - assert result == [PLUGIN_TEST_INIT_PY] - - -def test_create_base_config(config: Config): - """ - Test the backwards-compatibility shim to convert old plugin allow/deny list - to a config file. - """ - config.plugins_allowlist = ["a", "b"] - config.plugins_denylist = ["c", "d"] - - os.remove(config.plugins_config_file) - plugins_config = PluginsConfig.load_config( - plugins_config_file=config.plugins_config_file, - plugins_denylist=config.plugins_denylist, - plugins_allowlist=config.plugins_allowlist, - ) - - # Check the structure of the plugins config data - assert len(plugins_config.plugins) == 4 - assert plugins_config.get("a").enabled - assert plugins_config.get("b").enabled - assert not plugins_config.get("c").enabled - assert not plugins_config.get("d").enabled - - # Check the saved config file - with open(config.plugins_config_file, "r") as saved_config_file: - saved_config = yaml.load(saved_config_file, Loader=yaml.SafeLoader) - - assert saved_config == { - "a": {"enabled": True, "config": {}}, - "b": {"enabled": True, "config": {}}, - "c": {"enabled": False, "config": {}}, - "d": {"enabled": False, "config": {}}, - } - - -def test_load_config(config: Config): - """ - Test that the plugin config is loaded correctly from the plugins_config.yaml file. - """ - # Create a test config and write it to disk - test_config = { - "a": {"enabled": True, "config": {"api_key": "1234"}}, - "b": {"enabled": False, "config": {}}, - } - with open(config.plugins_config_file, "w+") as f: - f.write(yaml.dump(test_config)) - - # Load the config from disk - plugins_config = PluginsConfig.load_config( - plugins_config_file=config.plugins_config_file, - plugins_denylist=config.plugins_denylist, - plugins_allowlist=config.plugins_allowlist, - ) - - # Check that the loaded config is equal to the test config - assert len(plugins_config.plugins) == 2 - assert plugins_config.get("a").enabled - assert plugins_config.get("a").config == {"api_key": "1234"} - assert not plugins_config.get("b").enabled - assert plugins_config.get("b").config == {} diff --git a/docs/content/AutoGPT/configuration/options.md b/docs/content/AutoGPT/configuration/options.md index 0ff2c29c9cd..9003c7378f6 100644 --- a/docs/content/AutoGPT/configuration/options.md +++ b/docs/content/AutoGPT/configuration/options.md @@ -33,7 +33,6 @@ Configuration is controlled through the `Config` object. You can set configurati - `OPENAI_API_KEY`: *REQUIRED*- Your [OpenAI API Key](https://platform.openai.com/account/api-keys). - `OPENAI_ORGANIZATION`: Organization ID in OpenAI. Optional. - `PLAIN_OUTPUT`: Plain output, which disables the spinner. Default: False -- `PLUGINS_CONFIG_FILE`: Path of the Plugins Config file relative to the AutoGPT root directory. Default: plugins_config.yaml - `PROMPT_SETTINGS_FILE`: Location of the Prompt Settings file relative to the AutoGPT root directory. Default: prompt_settings.yaml - `REDIS_HOST`: Redis Host. Default: localhost - `REDIS_PASSWORD`: Redis Password. Optional. Default: