Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API via agent-protocol SDK #5044

Merged
merged 2 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 5 additions & 48 deletions autogpt/core/runner/cli_web_app/cli.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import contextlib
import pathlib
import shlex
import subprocess
import sys
import time

import click
import requests
import uvicorn
import yaml
from agent_protocol import Agent

from autogpt.core.runner.client_lib.shared_click_commands import (
DEFAULT_SETTINGS_FILE,
Expand All @@ -29,30 +23,18 @@ def autogpt():


@autogpt.command()
@click.option(
"host",
"--host",
default="localhost",
help="The host for the webserver.",
type=click.STRING,
)
@click.option(
"port",
"--port",
default=8080,
help="The port of the webserver.",
type=click.INT,
)
def server(host: str, port: int) -> None:
def server(port: int) -> None:
"""Run the Auto-GPT runner httpserver."""
click.echo("Running Auto-GPT runner httpserver...")
uvicorn.run(
"autogpt.core.runner.cli_web_app.server.api:app",
workers=1,
host=host,
port=port,
reload=True,
)
port = 8080
Agent.start(port)


@autogpt.command()
Expand All @@ -69,32 +51,7 @@ async def client(settings_file) -> None:
if settings_file.exists():
settings = yaml.safe_load(settings_file.read_text())

from autogpt.core.runner.cli_web_app.client.client import run

with autogpt_server():
run()


@contextlib.contextmanager
def autogpt_server():
host = "localhost"
port = 8080
cmd = shlex.split(
f"{sys.executable} autogpt/core/runner/cli_web_app/cli.py server --host {host} --port {port}"
)
server_process = subprocess.Popen(
args=cmd,
)
started = False

while not started:
try:
requests.get(f"http://{host}:{port}")
started = True
except requests.exceptions.ConnectionError:
time.sleep(0.2)
yield server_process
server_process.terminate()
# TODO: Call the API server with the settings and task, using the Python API client for agent protocol.


if __name__ == "__main__":
Expand Down
Empty file.
16 changes: 0 additions & 16 deletions autogpt/core/runner/cli_web_app/client/client.py

This file was deleted.

130 changes: 98 additions & 32 deletions autogpt/core/runner/cli_web_app/server/api.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,114 @@
import uuid
from pathlib import Path

from fastapi import APIRouter, FastAPI, Request
from agent_protocol import Agent as AgentProtocol
from agent_protocol import StepHandler, StepResult
from colorama import Fore

from autogpt.core.runner.cli_web_app.server.schema import InteractRequestBody
from autogpt.agents import Agent
from autogpt.app.main import UserFeedback
from autogpt.commands import COMMAND_CATEGORIES
from autogpt.config import AIConfig, Config, ConfigBuilder
from autogpt.logs import logger
from autogpt.memory.vector import get_memory
from autogpt.models.command_registry import CommandRegistry
from autogpt.prompts.prompt import DEFAULT_TRIGGERING_PROMPT
from autogpt.workspace import Workspace

router = APIRouter()
PROJECT_DIR = Path().resolve()


@router.post("/agents")
async def create_agent(request: Request):
"""Create a new agent."""
agent_id = uuid.uuid4().hex
return {"agent_id": agent_id}
async def task_handler(task_input) -> StepHandler:
agent = bootstrap_agent(task_input)

next_command_name: str | None
next_command_args: dict[str, str] | None

@router.post("/agents/{agent_id}")
async def interact(request: Request, agent_id: str, body: InteractRequestBody):
"""Interact with an agent."""
async def step_handler(step_input) -> StepResult:
result = await interaction_step(
agent,
step_input["user_input"],
step_input["user_feedback"],
next_command_name,
next_command_args,
)

# check headers
nonlocal next_command_name, next_command_args
next_command_name = result["next_step_command_name"] if result else None
next_command_args = result["next_step_command_args"] if result else None

# check if agent_id exists
if not result:
return StepResult(output=None, is_last=True)
return StepResult(output=result)

# get agent object from somewhere, e.g. a database/disk/global dict
return step_handler

# continue agent interaction with user input

async def interaction_step(
agent: Agent,
user_input,
user_feedback: UserFeedback | None,
command_name: str | None,
command_args: dict[str, str] | None,
):
"""Run one step of the interaction loop."""
if user_feedback == UserFeedback.EXIT:
return
if user_feedback == UserFeedback.TEXT:
command_name = "human_feedback"

result: str | None = None

if command_name is not None:
result = agent.execute(command_name, command_args, user_input)
if result is None:
logger.typewriter_log("SYSTEM: ", Fore.YELLOW, "Unable to execute command")
return

next_command_name, next_command_args, assistant_reply_dict = agent.think()

return {
"thoughts": {
"thoughts": {
"text": "text",
"reasoning": "reasoning",
"plan": "plan",
"criticism": "criticism",
"speak": "speak",
},
"commands": {
"name": "name",
"args": {"arg_1": "value_1", "arg_2": "value_2"},
},
},
"messages": ["message1", agent_id],
"config": agent.config,
"ai_config": agent.ai_config,
"result": result,
"assistant_reply_dict": assistant_reply_dict,
"next_step_command_name": next_command_name,
"next_step_command_args": next_command_args,
}


app = FastAPI()
app.include_router(router, prefix="/api/v1")
def bootstrap_agent(task):
config = ConfigBuilder.build_config_from_env(workdir=PROJECT_DIR)
config.continuous_mode = False
config.temperature = 0
config.plain_output = True
command_registry = get_command_registry(config)
config.memory_backend = "no_memory"
Workspace.set_workspace_directory(config)
Workspace.build_file_logger_path(config, config.workspace_path)
ai_config = AIConfig(
ai_name="Auto-GPT",
ai_role="a multi-purpose AI assistant.",
ai_goals=[task.user_input],
)
ai_config.command_registry = command_registry
return Agent(
memory=get_memory(config),
command_registry=command_registry,
ai_config=ai_config,
config=config,
triggering_prompt=DEFAULT_TRIGGERING_PROMPT,
workspace_directory=str(config.workspace_path),
)


def get_command_registry(config: Config):
command_registry = CommandRegistry()
enabled_command_categories = [
x for x in COMMAND_CATEGORIES if x not in config.disabled_command_categories
]
for command_category in enabled_command_categories:
command_registry.import_commands(command_category)
return command_registry


AgentProtocol.handle_task(task_handler)
36 changes: 0 additions & 36 deletions autogpt/core/runner/cli_web_app/server/schema.py

This file was deleted.

Empty file.
20 changes: 0 additions & 20 deletions autogpt/core/runner/cli_web_app/server/services/users.py

This file was deleted.

1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ prompt_toolkit>=3.0.38
pydantic
inflection
agbenchmark
agent-protocol>=0.1.1

# web server
fastapi
Expand Down