From 0c04bf56df1d336b06548bd957e1aba5df6bfa66 Mon Sep 17 00:00:00 2001 From: Reinier van der Leer Date: Mon, 16 Oct 2023 15:26:56 -0700 Subject: [PATCH] Add AutoGPT serve subcommand to run Agent Protocol server --- autogpts/autogpt/autogpt/__main__.py | 2 +- .../autogpt/agent_factory/generators.py | 4 +- .../autogpt/app/agent_protocol_server.py | 10 ++- autogpts/autogpt/autogpt/app/cli.py | 83 +++++++++++++++++-- autogpts/autogpt/autogpt/app/main.py | 80 ++++++++++++++---- .../core/runner/cli_web_app/server/api.py | 2 +- autogpts/autogpt/pyproject.toml | 4 +- 7 files changed, 158 insertions(+), 27 deletions(-) diff --git a/autogpts/autogpt/autogpt/__main__.py b/autogpts/autogpt/autogpt/__main__.py index 3b1122a4..e5b92456 100644 --- a/autogpts/autogpt/autogpt/__main__.py +++ b/autogpts/autogpt/autogpt/__main__.py @@ -2,4 +2,4 @@ import autogpt.app.cli if __name__ == "__main__": - autogpt.app.cli.main() + autogpt.app.cli.cli() diff --git a/autogpts/autogpt/autogpt/agent_factory/generators.py b/autogpts/autogpt/autogpt/agent_factory/generators.py index 4e0435fc..4d9702b8 100644 --- a/autogpts/autogpt/autogpt/agent_factory/generators.py +++ b/autogpts/autogpt/autogpt/agent_factory/generators.py @@ -2,9 +2,11 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from autogpt.agents.agent import Agent - from autogpt.config import AIDirectives, Config + from autogpt.config import Config from autogpt.core.resource.model_providers.schema import ChatModelProvider +from autogpt.config.ai_directives import AIDirectives + from .configurators import _configure_agent from .profile_generator import generate_agent_profile_for_task diff --git a/autogpts/autogpt/autogpt/app/agent_protocol_server.py b/autogpts/autogpt/autogpt/app/agent_protocol_server.py index ca0cb3be..6ec92024 100644 --- a/autogpts/autogpt/autogpt/app/agent_protocol_server.py +++ b/autogpts/autogpt/autogpt/app/agent_protocol_server.py @@ -1,4 +1,3 @@ -import asyncio import logging import os import pathlib @@ -11,6 +10,7 @@ from fastapi.responses import FileResponse, RedirectResponse, StreamingResponse from fastapi.staticfiles import StaticFiles from forge.sdk.db import AgentDB from forge.sdk.errors import NotFoundError +from forge.sdk.middlewares import AgentMiddleware from forge.sdk.routes.agent_protocol import base_router from forge.sdk.schema import ( Artifact, @@ -47,8 +47,9 @@ class AgentProtocolServer: self.llm_provider = llm_provider self.agent_manager = AgentManager(app_data_dir=app_config.app_data_dir) - def start(self, port: int = 8000, router: APIRouter = base_router): + async def start(self, port: int = 8000, router: APIRouter = base_router): """Start the agent server.""" + logger.debug("Starting the agent server...") config = HypercornConfig() config.bind = [f"localhost:{port}"] app = FastAPI( @@ -96,11 +97,14 @@ class AgentProtocolServer: f"Frontend not found. {frontend_path} does not exist. The frontend will not be available." ) + # Used to access the methods on this class from API route handlers + app.add_middleware(AgentMiddleware, agent=self) + config.loglevel = "ERROR" config.bind = [f"0.0.0.0:{port}"] logger.info(f"Agent server starting on http://localhost:{port}") - asyncio.run(hypercorn_serve(app, config)) + await hypercorn_serve(app, config) async def create_task(self, task_request: TaskRequestBody) -> Task: """ diff --git a/autogpts/autogpt/autogpt/app/cli.py b/autogpts/autogpt/autogpt/app/cli.py index ebbc9ea9..5c2468f9 100644 --- a/autogpts/autogpt/autogpt/app/cli.py +++ b/autogpts/autogpt/autogpt/app/cli.py @@ -5,7 +5,15 @@ from typing import Optional import click -@click.group(invoke_without_command=True) +@click.group(invoke_without_subcommand=True) +@click.pass_context +def cli(ctx: click.Context): + # Invoke `run` by default + if ctx.invoked_subcommand is None: + ctx.invoke(run) + + +@cli.command() @click.option("-c", "--continuous", is_flag=True, help="Enable Continuous Mode") @click.option( "--skip-reprompt", @@ -119,7 +127,7 @@ import click ), ) @click.pass_context -def main( +def run( ctx: click.Context, continuous: bool, continuous_limit: int, @@ -144,9 +152,8 @@ def main( override_directives: bool, ) -> None: """ - Welcome to AutoGPT an experimental open-source application showcasing the capabilities of the GPT-4 pushing the boundaries of AI. - - Start an AutoGPT assistant. + Sets up and runs an agent, based on the task specified by the user, or resumes an + existing agent. """ # Put imports inside function to avoid importing everything when starting the CLI from autogpt.app.main import run_auto_gpt @@ -177,5 +184,69 @@ def main( ) +@cli.command() +@click.option( + "--prompt-settings", + "-P", + type=click.Path(exists=True, dir_okay=False, path_type=Path), + help="Specifies which prompt_settings.yaml file to use.", +) +@click.option("--debug", is_flag=True, help="Enable Debug Mode") +@click.option("--gpt3only", is_flag=True, help="Enable GPT3.5 Only Mode") +@click.option("--gpt4only", is_flag=True, help="Enable GPT4 Only Mode") +@click.option( + "--use-memory", + "-m", + "memory_type", + type=str, + help="Defines which Memory backend to use", +) +@click.option( + "-b", + "--browser-name", + help="Specifies which web-browser to use when using selenium to scrape the web.", +) +@click.option( + "--allow-downloads", + is_flag=True, + help="Dangerous: Allows AutoGPT to download files natively.", +) +@click.option( + "--install-plugin-deps", + is_flag=True, + help="Installs external dependencies for 3rd party plugins.", +) +@click.pass_context +def serve( + ctx: click.Context, + prompt_settings: Optional[Path], + debug: bool, + gpt3only: bool, + gpt4only: bool, + memory_type: str, + browser_name: str, + allow_downloads: bool, + install_plugin_deps: bool, +) -> None: + """ + Starts an Agent Protocol compliant AutoGPT server, which creates a custom agent for + every task. + """ + # Put imports inside function to avoid importing everything when starting the CLI + from autogpt.app.main import run_auto_gpt_server + + if ctx.invoked_subcommand is None: + run_auto_gpt_server( + prompt_settings=prompt_settings, + debug=debug, + gpt3only=gpt3only, + gpt4only=gpt4only, + memory_type=memory_type, + browser_name=browser_name, + allow_downloads=allow_downloads, + install_plugin_deps=install_plugin_deps, + ) + + if __name__ == "__main__": - main() + cli() diff --git a/autogpts/autogpt/autogpt/app/main.py b/autogpts/autogpt/autogpt/app/main.py index ee3db474..1e60af89 100644 --- a/autogpts/autogpt/autogpt/app/main.py +++ b/autogpts/autogpt/autogpt/app/main.py @@ -10,6 +10,7 @@ from types import FrameType from typing import TYPE_CHECKING, Optional from colorama import Fore, Style +from forge.sdk.db import AgentDB from pydantic import SecretStr if TYPE_CHECKING: @@ -20,20 +21,6 @@ from autogpt.agent_factory.profile_generator import generate_agent_profile_for_t from autogpt.agent_manager import AgentManager from autogpt.agents import AgentThoughts, CommandArgs, CommandName from autogpt.agents.utils.exceptions import AgentTerminated, InvalidAgentResponseError -from autogpt.app.configurator import apply_overrides_to_config -from autogpt.app.setup import ( - apply_overrides_to_ai_settings, - interactively_revise_ai_settings, -) -from autogpt.app.spinner import Spinner -from autogpt.app.utils import ( - clean_input, - get_legal_warning, - markdown_to_ansi_style, - print_git_branch_info, - print_motd, - print_python_version_info, -) from autogpt.config import ( AIDirectives, AIProfile, @@ -49,6 +36,22 @@ from autogpt.logs.helpers import print_attribute, speak from autogpt.plugins import scan_plugins from scripts.install_plugin_deps import install_plugin_dependencies +from .agent_protocol_server import AgentProtocolServer +from .configurator import apply_overrides_to_config +from .setup import ( + apply_overrides_to_ai_settings, + interactively_revise_ai_settings, +) +from .spinner import Spinner +from .utils import ( + clean_input, + get_legal_warning, + markdown_to_ansi_style, + print_git_branch_info, + print_motd, + print_python_version_info, +) + @coroutine async def run_auto_gpt( @@ -293,6 +296,55 @@ async def run_auto_gpt( agent.state.save_to_json_file(agent.file_manager.state_file_path) +@coroutine +async def run_auto_gpt_server( + prompt_settings: Optional[Path], + debug: bool, + gpt3only: bool, + gpt4only: bool, + memory_type: str, + browser_name: str, + allow_downloads: bool, + install_plugin_deps: bool, +): + config = ConfigBuilder.build_config_from_env() + + # TODO: fill in llm values here + assert_config_has_openai_api_key(config) + + apply_overrides_to_config( + config=config, + prompt_settings_file=prompt_settings, + debug=debug, + gpt3only=gpt3only, + gpt4only=gpt4only, + memory_type=memory_type, + browser_name=browser_name, + allow_downloads=allow_downloads, + ) + + # Set up logging module + configure_logging( + debug_mode=debug, + plain_output=config.plain_output, + tts_config=config.tts_config, + ) + + llm_provider = _configure_openai_provider(config) + + if install_plugin_deps: + install_plugin_dependencies() + + config.plugins = scan_plugins(config, config.debug_mode) + + # Set up & start server + database = AgentDB("sqlite:///data/ap_server.db", debug_enabled=False) + server = AgentProtocolServer( + app_config=config, database=database, llm_provider=llm_provider + ) + await server.start() + + def _configure_openai_provider(config: Config) -> OpenAIProvider: """Create a configured OpenAIProvider object. diff --git a/autogpts/autogpt/autogpt/core/runner/cli_web_app/server/api.py b/autogpts/autogpt/autogpt/core/runner/cli_web_app/server/api.py index 07ccc3fc..d1cbc2fd 100644 --- a/autogpts/autogpt/autogpt/core/runner/cli_web_app/server/api.py +++ b/autogpts/autogpt/autogpt/core/runner/cli_web_app/server/api.py @@ -65,7 +65,7 @@ async def interaction_step( ) return - next_command_name, next_command_args, assistant_reply_dict = agent.think() + next_command_name, next_command_args, assistant_reply_dict = agent.propose_action() return { "config": agent.config, diff --git a/autogpts/autogpt/pyproject.toml b/autogpts/autogpt/pyproject.toml index 83884357..70ee0109 100644 --- a/autogpts/autogpt/pyproject.toml +++ b/autogpts/autogpt/pyproject.toml @@ -16,7 +16,9 @@ packages = [{ include = "autogpt" }] [tool.poetry.scripts] -autogpt = "autogpt.app.cli:main" +autogpt = "autogpt.app.cli:run" +run = "autogpt.app.cli:run" +serve = "autogpt.app.cli:serve" [tool.poetry.dependencies]