mirror of
https://github.com/aljazceru/Auto-GPT.git
synced 2026-01-11 10:14:32 +01:00
Add AgentFactory and replace AI Goals by AI Directives + Task
This commit is contained in:
116
autogpts/autogpt/autogpt/agent_factory/configurators.py
Normal file
116
autogpts/autogpt/autogpt/agent_factory/configurators.py
Normal file
@@ -0,0 +1,116 @@
|
||||
from typing import Optional
|
||||
|
||||
from autogpt.agent_manager import AgentManager
|
||||
from autogpt.agents.agent import Agent, AgentConfiguration, AgentSettings
|
||||
from autogpt.commands import COMMAND_CATEGORIES
|
||||
from autogpt.config import AIProfile, AIDirectives, Config
|
||||
from autogpt.core.resource.model_providers import ChatModelProvider
|
||||
from autogpt.logs.config import configure_chat_plugins
|
||||
from autogpt.logs.helpers import print_attribute
|
||||
from autogpt.models.command_registry import CommandRegistry
|
||||
from autogpt.plugins import scan_plugins
|
||||
|
||||
|
||||
def create_agent(
|
||||
task: str,
|
||||
ai_profile: AIProfile,
|
||||
app_config: Config,
|
||||
llm_provider: ChatModelProvider,
|
||||
directives: Optional[AIDirectives] = None,
|
||||
) -> Agent:
|
||||
if not task:
|
||||
raise ValueError("No task specified for new agent")
|
||||
if not directives:
|
||||
directives = AIDirectives.from_file(app_config.prompt_settings_file)
|
||||
|
||||
agent = _configure_agent(
|
||||
task=task,
|
||||
ai_profile=ai_profile,
|
||||
directives=directives,
|
||||
app_config=app_config,
|
||||
llm_provider=llm_provider,
|
||||
)
|
||||
|
||||
agent.state.agent_id = AgentManager.generate_id(agent.ai_profile.ai_name)
|
||||
|
||||
return agent
|
||||
|
||||
|
||||
def configure_agent_with_state(
|
||||
state: AgentSettings,
|
||||
app_config: Config,
|
||||
llm_provider: ChatModelProvider,
|
||||
) -> Agent:
|
||||
return _configure_agent(
|
||||
state=state,
|
||||
app_config=app_config,
|
||||
llm_provider=llm_provider,
|
||||
)
|
||||
|
||||
|
||||
def _configure_agent(
|
||||
app_config: Config,
|
||||
llm_provider: ChatModelProvider,
|
||||
task: str = "",
|
||||
ai_profile: Optional[AIProfile] = None,
|
||||
directives: Optional[AIDirectives] = None,
|
||||
state: Optional[AgentSettings] = None,
|
||||
) -> Agent:
|
||||
if not (state or task and ai_profile and directives):
|
||||
raise TypeError(
|
||||
"Either (state) or (task, ai_profile, directives) must be specified"
|
||||
)
|
||||
|
||||
app_config.plugins = scan_plugins(app_config, app_config.debug_mode)
|
||||
configure_chat_plugins(app_config)
|
||||
|
||||
# Create a CommandRegistry instance and scan default folder
|
||||
command_registry = CommandRegistry.with_command_modules(
|
||||
modules=COMMAND_CATEGORIES,
|
||||
config=app_config,
|
||||
)
|
||||
|
||||
agent_state = state or create_agent_state(
|
||||
task=task,
|
||||
ai_profile=ai_profile,
|
||||
directives=directives,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
# TODO: configure memory
|
||||
|
||||
print_attribute("Configured Browser", app_config.selenium_web_browser)
|
||||
|
||||
return Agent(
|
||||
settings=agent_state,
|
||||
llm_provider=llm_provider,
|
||||
command_registry=command_registry,
|
||||
legacy_config=app_config,
|
||||
)
|
||||
|
||||
|
||||
def create_agent_state(
|
||||
task: str,
|
||||
ai_profile: AIProfile,
|
||||
directives: AIDirectives,
|
||||
app_config: Config,
|
||||
) -> AgentSettings:
|
||||
agent_prompt_config = Agent.default_settings.prompt_config.copy(deep=True)
|
||||
agent_prompt_config.use_functions_api = app_config.openai_functions
|
||||
|
||||
return AgentSettings(
|
||||
name=Agent.default_settings.name,
|
||||
description=Agent.default_settings.description,
|
||||
task=task,
|
||||
ai_profile=ai_profile,
|
||||
directives=directives,
|
||||
config=AgentConfiguration(
|
||||
fast_llm=app_config.fast_llm,
|
||||
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,
|
||||
),
|
||||
prompt_config=agent_prompt_config,
|
||||
history=Agent.default_settings.history.copy(deep=True),
|
||||
)
|
||||
29
autogpts/autogpt/autogpt/agent_factory/generators.py
Normal file
29
autogpts/autogpt/autogpt/agent_factory/generators.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from autogpt.agents.agent import Agent
|
||||
from autogpt.config import AIDirectives, Config
|
||||
from autogpt.core.resource.model_providers.schema import ChatModelProvider
|
||||
|
||||
from .configurators import _configure_agent
|
||||
from .profile_generator import generate_agent_profile_for_task
|
||||
|
||||
|
||||
async def generate_agent_for_task(
|
||||
task: str,
|
||||
app_config: "Config",
|
||||
llm_provider: "ChatModelProvider",
|
||||
) -> "Agent":
|
||||
base_directives = AIDirectives.from_file(app_config.ai_settings_file)
|
||||
ai_profile, task_directives = await generate_agent_profile_for_task(
|
||||
task=task,
|
||||
app_config=app_config,
|
||||
llm_provider=llm_provider,
|
||||
)
|
||||
return _configure_agent(
|
||||
task=task,
|
||||
ai_profile=ai_profile,
|
||||
directives=base_directives + task_directives,
|
||||
app_config=app_config,
|
||||
llm_provider=llm_provider,
|
||||
)
|
||||
216
autogpts/autogpt/autogpt/agent_factory/profile_generator.py
Normal file
216
autogpts/autogpt/autogpt/agent_factory/profile_generator.py
Normal file
@@ -0,0 +1,216 @@
|
||||
import logging
|
||||
|
||||
from autogpt.config import AIProfile, AIDirectives, Config
|
||||
from autogpt.core.configuration import SystemConfiguration, UserConfigurable
|
||||
from autogpt.core.prompting import (
|
||||
ChatPrompt,
|
||||
LanguageModelClassification,
|
||||
PromptStrategy,
|
||||
)
|
||||
from autogpt.core.prompting.utils import json_loads
|
||||
from autogpt.core.resource.model_providers.schema import (
|
||||
AssistantChatMessageDict,
|
||||
ChatMessage,
|
||||
ChatModelProvider,
|
||||
CompletionModelFunction,
|
||||
)
|
||||
from autogpt.core.utils.json_schema import JSONSchema
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AgentProfileGeneratorConfiguration(SystemConfiguration):
|
||||
model_classification: LanguageModelClassification = UserConfigurable(
|
||||
default=LanguageModelClassification.SMART_MODEL
|
||||
)
|
||||
system_prompt: str = UserConfigurable(
|
||||
default=(
|
||||
"Your job is to respond to a user-defined task, given in triple quotes, by "
|
||||
"invoking the `create_agent` function to generate an autonomous agent to "
|
||||
"complete the task. "
|
||||
"You should supply a role-based name for the agent (_GPT), "
|
||||
"an informative description for what the agent does, and "
|
||||
"1 to 5 directives in each of the categories Best Practices and Constraints, "
|
||||
"that are optimally aligned with the successful completion "
|
||||
"of its assigned task.\n"
|
||||
"\n"
|
||||
"Example Input:\n"
|
||||
'"""Help me with marketing my business"""\n\n'
|
||||
"Example Function Call:\n"
|
||||
"```\n"
|
||||
"{"
|
||||
'"name": "create_agent",'
|
||||
' "arguments": {'
|
||||
'"name": "CMOGPT",'
|
||||
' "description": "a professional digital marketer AI that assists Solopreneurs in'
|
||||
" growing their businesses by providing world-class expertise in solving"
|
||||
' marketing problems for SaaS, content products, agencies, and more.",'
|
||||
' "directives": {'
|
||||
' "best_practices": ['
|
||||
'"Engage in effective problem-solving, prioritization, planning, and'
|
||||
" supporting execution to address your marketing needs as your virtual Chief"
|
||||
' Marketing Officer.",'
|
||||
' "Provide specific, actionable, and concise advice to help you make'
|
||||
" informed decisions without the use of platitudes or overly wordy"
|
||||
' explanations.",'
|
||||
' "Identify and prioritize quick wins and cost-effective campaigns that'
|
||||
' maximize results with minimal time and budget investment.",'
|
||||
' "Proactively take the lead in guiding you and offering suggestions when'
|
||||
" faced with unclear information or uncertainty to ensure your marketing"
|
||||
' strategy remains on track."'
|
||||
"]" # best_practices
|
||||
"}" # directives
|
||||
"}" # arguments
|
||||
"}\n"
|
||||
"```"
|
||||
)
|
||||
)
|
||||
user_prompt_template: str = UserConfigurable(default='"""{user_objective}"""')
|
||||
create_agent_function: dict = UserConfigurable(
|
||||
default=CompletionModelFunction(
|
||||
name="create_agent",
|
||||
description="Create a new autonomous AI agent to complete a given task.",
|
||||
parameters={
|
||||
"name": JSONSchema(
|
||||
type=JSONSchema.Type.STRING,
|
||||
description="A short role-based name for an autonomous agent.",
|
||||
required=True,
|
||||
),
|
||||
"description": JSONSchema(
|
||||
type=JSONSchema.Type.STRING,
|
||||
description="An informative one sentence description of what the AI agent does",
|
||||
required=True,
|
||||
),
|
||||
"directives": JSONSchema(
|
||||
type=JSONSchema.Type.OBJECT,
|
||||
properties={
|
||||
"best_practices": JSONSchema(
|
||||
type=JSONSchema.Type.ARRAY,
|
||||
minItems=1,
|
||||
maxItems=5,
|
||||
items=JSONSchema(
|
||||
type=JSONSchema.Type.STRING,
|
||||
),
|
||||
description=(
|
||||
"One to five highly effective best practices that are"
|
||||
" optimally aligned with the completion of the given task."
|
||||
),
|
||||
required=True,
|
||||
),
|
||||
"constraints": JSONSchema(
|
||||
type=JSONSchema.Type.ARRAY,
|
||||
minItems=1,
|
||||
maxItems=5,
|
||||
items=JSONSchema(
|
||||
type=JSONSchema.Type.STRING,
|
||||
),
|
||||
description=(
|
||||
"One to five highly effective constraints that are"
|
||||
" optimally aligned with the completion of the given task."
|
||||
),
|
||||
required=True,
|
||||
),
|
||||
},
|
||||
required=True,
|
||||
),
|
||||
},
|
||||
).schema
|
||||
)
|
||||
|
||||
|
||||
class AgentProfileGenerator(PromptStrategy):
|
||||
default_configuration: AgentProfileGeneratorConfiguration = AgentProfileGeneratorConfiguration()
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
model_classification: LanguageModelClassification,
|
||||
system_prompt: str,
|
||||
user_prompt_template: str,
|
||||
create_agent_function: dict,
|
||||
):
|
||||
self._model_classification = model_classification
|
||||
self._system_prompt_message = system_prompt
|
||||
self._user_prompt_template = user_prompt_template
|
||||
self._create_agent_function = CompletionModelFunction.parse(
|
||||
create_agent_function
|
||||
)
|
||||
|
||||
@property
|
||||
def model_classification(self) -> LanguageModelClassification:
|
||||
return self._model_classification
|
||||
|
||||
def build_prompt(self, user_objective: str = "", **kwargs) -> ChatPrompt:
|
||||
system_message = ChatMessage.system(self._system_prompt_message)
|
||||
user_message = ChatMessage.user(
|
||||
self._user_prompt_template.format(
|
||||
user_objective=user_objective,
|
||||
)
|
||||
)
|
||||
prompt = ChatPrompt(
|
||||
messages=[system_message, user_message],
|
||||
functions=[self._create_agent_function],
|
||||
)
|
||||
return prompt
|
||||
|
||||
def parse_response_content(
|
||||
self,
|
||||
response_content: AssistantChatMessageDict,
|
||||
) -> tuple[AIProfile, AIDirectives]:
|
||||
"""Parse the actual text response from the objective model.
|
||||
|
||||
Args:
|
||||
response_content: The raw response content from the objective model.
|
||||
|
||||
Returns:
|
||||
The parsed response.
|
||||
|
||||
"""
|
||||
try:
|
||||
arguments = json_loads(response_content["function_call"]["arguments"])
|
||||
ai_profile = AIProfile(
|
||||
ai_name=arguments["name"],
|
||||
ai_role=arguments["description"],
|
||||
)
|
||||
ai_directives = AIDirectives(
|
||||
best_practices=arguments["directives"]["best_practices"],
|
||||
constraints=arguments["directives"]["constraints"],
|
||||
resources=[],
|
||||
)
|
||||
except KeyError:
|
||||
logger.debug(f"Failed to parse this response content: {response_content}")
|
||||
raise
|
||||
return ai_profile, ai_directives
|
||||
|
||||
|
||||
async def generate_agent_profile_for_task(
|
||||
task: str,
|
||||
app_config: Config,
|
||||
llm_provider: ChatModelProvider,
|
||||
) -> tuple[AIProfile, AIDirectives]:
|
||||
"""Generates an AIConfig object from the given string.
|
||||
|
||||
Returns:
|
||||
AIConfig: The AIConfig object tailored to the user's input
|
||||
"""
|
||||
agent_profile_generator = AgentProfileGenerator(
|
||||
**AgentProfileGenerator.default_configuration.dict() # HACK
|
||||
)
|
||||
|
||||
prompt = agent_profile_generator.build_prompt(task)
|
||||
|
||||
# Call LLM with the string as user input
|
||||
output = (
|
||||
await llm_provider.create_chat_completion(
|
||||
prompt.messages,
|
||||
model_name=app_config.smart_llm,
|
||||
functions=prompt.functions,
|
||||
)
|
||||
).response
|
||||
|
||||
# Debug LLM Output
|
||||
logger.debug(f"AI Config Generator Raw Output: {output}")
|
||||
|
||||
# Parse the output
|
||||
ai_profile, ai_directives = agent_profile_generator.parse_response_content(output)
|
||||
|
||||
return ai_profile, ai_directives
|
||||
@@ -137,6 +137,9 @@ class BaseAgentSettings(SystemSettings):
|
||||
)
|
||||
"""Directives (general instructional guidelines) for the agent."""
|
||||
|
||||
task: str = "Terminate immediately" # FIXME: placeholder for forge.sdk.schema.Task
|
||||
"""The user-given task that the agent is working on."""
|
||||
|
||||
config: BaseAgentConfiguration = Field(default_factory=BaseAgentConfiguration)
|
||||
"""The configuration for this BaseAgent subsystem instance."""
|
||||
|
||||
@@ -165,7 +168,7 @@ class BaseAgent(Configurable[BaseAgentSettings], ABC):
|
||||
self.state = settings
|
||||
self.config = settings.config
|
||||
self.ai_profile = settings.ai_profile
|
||||
self.ai_directives = settings.directives
|
||||
self.directives = settings.directives
|
||||
self.event_history = settings.history
|
||||
|
||||
self.legacy_config = legacy_config
|
||||
@@ -288,13 +291,14 @@ class BaseAgent(Configurable[BaseAgentSettings], ABC):
|
||||
if not plugin.can_handle_post_prompt():
|
||||
continue
|
||||
plugin.post_prompt(scratchpad)
|
||||
ai_directives = self.ai_directives.copy(deep=True)
|
||||
ai_directives = self.directives.copy(deep=True)
|
||||
ai_directives.resources += scratchpad.resources
|
||||
ai_directives.constraints += scratchpad.constraints
|
||||
ai_directives.best_practices += scratchpad.best_practices
|
||||
extra_commands += list(scratchpad.commands.values())
|
||||
|
||||
prompt = self.prompt_strategy.build_prompt(
|
||||
task=self.state.task,
|
||||
ai_profile=self.ai_profile,
|
||||
ai_directives=ai_directives,
|
||||
commands=get_openai_command_specs(
|
||||
|
||||
@@ -193,6 +193,7 @@ class OneShotAgentPromptStrategy(PromptStrategy):
|
||||
def build_prompt(
|
||||
self,
|
||||
*,
|
||||
task: str,
|
||||
ai_profile: AIProfile,
|
||||
ai_directives: AIDirectives,
|
||||
commands: list[CompletionModelFunction],
|
||||
@@ -223,6 +224,9 @@ class OneShotAgentPromptStrategy(PromptStrategy):
|
||||
)
|
||||
system_prompt_tlength = count_message_tokens(ChatMessage.system(system_prompt))
|
||||
|
||||
user_task = f'"""{task}"""'
|
||||
user_task_tlength = count_message_tokens(ChatMessage.user(user_task))
|
||||
|
||||
response_format_instr = self.response_format_instruction(
|
||||
self.config.use_functions_api
|
||||
)
|
||||
@@ -238,6 +242,7 @@ class OneShotAgentPromptStrategy(PromptStrategy):
|
||||
max_tokens=(
|
||||
max_prompt_tokens
|
||||
- system_prompt_tlength
|
||||
- user_task_tlength
|
||||
- final_instruction_tlength
|
||||
- count_message_tokens(extra_messages)
|
||||
),
|
||||
@@ -250,6 +255,7 @@ class OneShotAgentPromptStrategy(PromptStrategy):
|
||||
prompt = ChatPrompt(
|
||||
messages=[
|
||||
ChatMessage.system(system_prompt),
|
||||
ChatMessage.user(user_task),
|
||||
*extra_messages,
|
||||
final_instruction_msg,
|
||||
],
|
||||
@@ -278,7 +284,12 @@ class OneShotAgentPromptStrategy(PromptStrategy):
|
||||
best_practices=format_numbered_list(ai_directives.best_practices),
|
||||
)
|
||||
]
|
||||
+ self._generate_goals_info(ai_profile.ai_goals)
|
||||
+ [
|
||||
"## Your Task\n"
|
||||
"The user will specify a task for you to execute, in triple quotes,"
|
||||
" in the next message. Your job is to complete the task while following"
|
||||
" your directives as given above, and terminate when your task is done."
|
||||
]
|
||||
)
|
||||
|
||||
# Join non-empty parts together into paragraph format
|
||||
@@ -395,24 +406,6 @@ class OneShotAgentPromptStrategy(PromptStrategy):
|
||||
]
|
||||
return []
|
||||
|
||||
def _generate_goals_info(self, goals: list[str]) -> list[str]:
|
||||
"""Generates the goals information part of the prompt.
|
||||
|
||||
Returns:
|
||||
str: The goals information part of the prompt.
|
||||
"""
|
||||
if goals:
|
||||
return [
|
||||
"\n".join(
|
||||
[
|
||||
"## Goals",
|
||||
"For your task, you must fulfill the following goals:",
|
||||
*[f"{i+1}. {goal}" for i, goal in enumerate(goals)],
|
||||
]
|
||||
)
|
||||
]
|
||||
return []
|
||||
|
||||
def _generate_commands_list(self, commands: list[CompletionModelFunction]) -> str:
|
||||
"""Lists the commands available to the agent.
|
||||
|
||||
|
||||
@@ -84,10 +84,39 @@ import click
|
||||
help="AI role override",
|
||||
)
|
||||
@click.option(
|
||||
"--ai-goal",
|
||||
"--constraint",
|
||||
type=str,
|
||||
multiple=True,
|
||||
help="AI goal override; may be used multiple times to pass multiple goals",
|
||||
help=(
|
||||
"Add or override AI constraints to include in the prompt;"
|
||||
" may be used multiple times to pass multiple constraints"
|
||||
),
|
||||
)
|
||||
@click.option(
|
||||
"--resource",
|
||||
type=str,
|
||||
multiple=True,
|
||||
help=(
|
||||
"Add or override AI resources to include in the prompt;"
|
||||
" may be used multiple times to pass multiple resources"
|
||||
),
|
||||
)
|
||||
@click.option(
|
||||
"--best-practice",
|
||||
type=str,
|
||||
multiple=True,
|
||||
help=(
|
||||
"Add or override AI best practices to include in the prompt;"
|
||||
" may be used multiple times to pass multiple best practices"
|
||||
),
|
||||
)
|
||||
@click.option(
|
||||
"--override-directives",
|
||||
is_flag=True,
|
||||
help=(
|
||||
"If specified, --constraint, --resource and --best-practice will override"
|
||||
" the AI's directives instead of being appended to them"
|
||||
),
|
||||
)
|
||||
@click.pass_context
|
||||
def main(
|
||||
@@ -109,7 +138,10 @@ def main(
|
||||
install_plugin_deps: bool,
|
||||
ai_name: Optional[str],
|
||||
ai_role: Optional[str],
|
||||
ai_goal: tuple[str],
|
||||
resource: tuple[str],
|
||||
constraint: tuple[str],
|
||||
best_practice: tuple[str],
|
||||
override_directives: bool,
|
||||
) -> None:
|
||||
"""
|
||||
Welcome to AutoGPT an experimental open-source application showcasing the capabilities of the GPT-4 pushing the boundaries of AI.
|
||||
@@ -136,9 +168,12 @@ def main(
|
||||
skip_news=skip_news,
|
||||
workspace_directory=workspace_directory,
|
||||
install_plugin_deps=install_plugin_deps,
|
||||
ai_name=ai_name,
|
||||
ai_role=ai_role,
|
||||
ai_goals=ai_goal,
|
||||
override_ai_name=ai_name,
|
||||
override_ai_role=ai_role,
|
||||
resources=list(resource),
|
||||
constraints=list(constraint),
|
||||
best_practices=list(best_practice),
|
||||
override_directives=override_directives,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -6,16 +6,24 @@ import signal
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from types import FrameType
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from colorama import Fore, Style
|
||||
from pydantic import SecretStr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from autogpt.agents.agent import Agent
|
||||
|
||||
from autogpt.agent_factory.configurators import create_agent
|
||||
from autogpt.agent_factory.profile_generator import generate_agent_profile_for_task
|
||||
from autogpt.agent_manager import AgentManager
|
||||
from autogpt.agents import AgentThoughts, CommandArgs, CommandName
|
||||
from autogpt.agents.agent import Agent, AgentConfiguration, AgentSettings
|
||||
from autogpt.agents.utils.exceptions import InvalidAgentResponseError
|
||||
from autogpt.app.configurator import apply_overrides_to_config
|
||||
from autogpt.app.setup import interactive_ai_profile_setup
|
||||
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,
|
||||
@@ -25,7 +33,6 @@ from autogpt.app.utils import (
|
||||
print_motd,
|
||||
print_python_version_info,
|
||||
)
|
||||
from autogpt.commands import COMMAND_CATEGORIES
|
||||
from autogpt.config import (
|
||||
AIDirectives,
|
||||
AIProfile,
|
||||
@@ -33,16 +40,11 @@ from autogpt.config import (
|
||||
ConfigBuilder,
|
||||
assert_config_has_openai_api_key,
|
||||
)
|
||||
from autogpt.core.resource.model_providers import (
|
||||
ChatModelProvider,
|
||||
ModelProviderCredentials,
|
||||
)
|
||||
from autogpt.core.resource.model_providers import ModelProviderCredentials
|
||||
from autogpt.core.resource.model_providers.openai import OpenAIProvider
|
||||
from autogpt.core.runner.client_lib.utils import coroutine
|
||||
from autogpt.llm.api_manager import ApiManager
|
||||
from autogpt.logs.config import configure_chat_plugins, configure_logging
|
||||
from autogpt.logs.helpers import print_attribute, speak
|
||||
from autogpt.models.command_registry import CommandRegistry
|
||||
from autogpt.plugins import scan_plugins
|
||||
from scripts.install_plugin_deps import install_plugin_dependencies
|
||||
|
||||
@@ -62,11 +64,14 @@ async def run_auto_gpt(
|
||||
browser_name: str,
|
||||
allow_downloads: bool,
|
||||
skip_news: bool,
|
||||
workspace_directory: str | Path,
|
||||
workspace_directory: Path,
|
||||
install_plugin_deps: bool,
|
||||
ai_name: Optional[str] = None,
|
||||
ai_role: Optional[str] = None,
|
||||
ai_goals: tuple[str] = tuple(),
|
||||
override_ai_name: str = "",
|
||||
override_ai_role: str = "",
|
||||
resources: Optional[list[str]] = None,
|
||||
constraints: Optional[list[str]] = None,
|
||||
best_practices: Optional[list[str]] = None,
|
||||
override_directives: bool = False,
|
||||
):
|
||||
config = ConfigBuilder.build_config_from_env()
|
||||
|
||||
@@ -123,44 +128,58 @@ async def run_auto_gpt(
|
||||
config.plugins = scan_plugins(config, config.debug_mode)
|
||||
configure_chat_plugins(config)
|
||||
|
||||
# Create a CommandRegistry instance and scan default folder
|
||||
command_registry = CommandRegistry.with_command_modules(COMMAND_CATEGORIES, config)
|
||||
|
||||
ai_profile = await construct_main_ai_profile(
|
||||
######################
|
||||
# Set up a new Agent #
|
||||
######################
|
||||
task = await clean_input(
|
||||
config,
|
||||
llm_provider=llm_provider,
|
||||
name=ai_name,
|
||||
role=ai_role,
|
||||
goals=ai_goals,
|
||||
"Enter the task that you want AutoGPT to execute,"
|
||||
" with as much detail as possible:",
|
||||
)
|
||||
ai_directives = AIDirectives.from_file(config.prompt_settings_file)
|
||||
base_ai_directives = AIDirectives.from_file(config.prompt_settings_file)
|
||||
|
||||
agent_prompt_config = Agent.default_settings.prompt_config.copy(deep=True)
|
||||
agent_prompt_config.use_functions_api = config.openai_functions
|
||||
|
||||
agent_settings = AgentSettings(
|
||||
name=Agent.default_settings.name,
|
||||
description=Agent.default_settings.description,
|
||||
ai_profile, task_oriented_ai_directives = await generate_agent_profile_for_task(
|
||||
task,
|
||||
app_config=config,
|
||||
llm_provider=llm_provider,
|
||||
)
|
||||
ai_directives = base_ai_directives + task_oriented_ai_directives
|
||||
apply_overrides_to_ai_settings(
|
||||
ai_profile=ai_profile,
|
||||
directives=ai_directives,
|
||||
config=AgentConfiguration(
|
||||
fast_llm=config.fast_llm,
|
||||
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),
|
||||
override_name=override_ai_name,
|
||||
override_role=override_ai_role,
|
||||
resources=resources,
|
||||
constraints=constraints,
|
||||
best_practices=best_practices,
|
||||
replace_directives=override_directives,
|
||||
)
|
||||
|
||||
print_attribute("Configured Browser", config.selenium_web_browser)
|
||||
# If any of these are specified as arguments,
|
||||
# assume the user doesn't want to revise them
|
||||
if not any(
|
||||
[
|
||||
override_ai_name,
|
||||
override_ai_role,
|
||||
resources,
|
||||
constraints,
|
||||
best_practices,
|
||||
]
|
||||
):
|
||||
ai_profile, ai_directives = await interactively_revise_ai_settings(
|
||||
ai_profile=ai_profile,
|
||||
directives=ai_directives,
|
||||
app_config=config,
|
||||
)
|
||||
else:
|
||||
logger.info("AI config overrides specified through CLI; skipping revision")
|
||||
|
||||
agent = Agent(
|
||||
settings=agent_settings,
|
||||
agent = create_agent(
|
||||
task=task,
|
||||
ai_profile=ai_profile,
|
||||
directives=ai_directives,
|
||||
app_config=config,
|
||||
llm_provider=llm_provider,
|
||||
command_registry=command_registry,
|
||||
legacy_config=config,
|
||||
)
|
||||
agent.attach_fs(config.app_data_dir / "agents" / "AutoGPT") # HACK
|
||||
|
||||
@@ -223,7 +242,7 @@ class UserFeedback(str, enum.Enum):
|
||||
|
||||
|
||||
async def run_interaction_loop(
|
||||
agent: Agent,
|
||||
agent: "Agent",
|
||||
) -> None:
|
||||
"""Run the main interaction loop for the agent.
|
||||
|
||||
@@ -482,83 +501,6 @@ async def get_user_feedback(
|
||||
return user_feedback, user_input, new_cycles_remaining
|
||||
|
||||
|
||||
async def construct_main_ai_profile(
|
||||
config: Config,
|
||||
llm_provider: ChatModelProvider,
|
||||
name: Optional[str] = None,
|
||||
role: Optional[str] = None,
|
||||
goals: tuple[str] = tuple(),
|
||||
) -> AIProfile:
|
||||
"""Construct the prompt for the AI to respond to
|
||||
|
||||
Returns:
|
||||
str: The prompt string
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ai_profile = AIProfile.load(config.ai_settings_file)
|
||||
|
||||
# Apply overrides
|
||||
if name:
|
||||
ai_profile.ai_name = name
|
||||
if role:
|
||||
ai_profile.ai_role = role
|
||||
if goals:
|
||||
ai_profile.ai_goals = list(goals)
|
||||
|
||||
if (
|
||||
all([name, role, goals])
|
||||
or config.skip_reprompt
|
||||
and all([ai_profile.ai_name, ai_profile.ai_role, ai_profile.ai_goals])
|
||||
):
|
||||
print_attribute("Name :", ai_profile.ai_name)
|
||||
print_attribute("Role :", ai_profile.ai_role)
|
||||
print_attribute("Goals:", ai_profile.ai_goals)
|
||||
print_attribute(
|
||||
"API Budget:",
|
||||
"infinite" if ai_profile.api_budget <= 0 else f"${ai_profile.api_budget}",
|
||||
)
|
||||
elif all([ai_profile.ai_name, ai_profile.ai_role, ai_profile.ai_goals]):
|
||||
logger.info(
|
||||
extra={"title": f"{Fore.GREEN}Welcome back!{Fore.RESET}"},
|
||||
msg=f"Would you like me to return to being {ai_profile.ai_name}?",
|
||||
)
|
||||
should_continue = await clean_input(
|
||||
config,
|
||||
f"""Continue with the last settings?
|
||||
Name: {ai_profile.ai_name}
|
||||
Role: {ai_profile.ai_role}
|
||||
Goals: {ai_profile.ai_goals}
|
||||
API Budget: {"infinite" if ai_profile.api_budget <= 0 else f"${ai_profile.api_budget}"}
|
||||
Continue ({config.authorise_key}/{config.exit_key}): """,
|
||||
)
|
||||
if should_continue.lower() == config.exit_key:
|
||||
ai_profile = AIProfile()
|
||||
|
||||
if any([not ai_profile.ai_name, not ai_profile.ai_role, not ai_profile.ai_goals]):
|
||||
ai_profile = await interactive_ai_profile_setup(config, llm_provider)
|
||||
ai_profile.save(config.ai_settings_file)
|
||||
|
||||
# set the total api budget
|
||||
api_manager = ApiManager()
|
||||
api_manager.set_total_budget(ai_profile.api_budget)
|
||||
|
||||
# Agent Created, print message
|
||||
logger.info(
|
||||
f"{Fore.LIGHTBLUE_EX}{ai_profile.ai_name}{Fore.RESET} has been created with the following details:",
|
||||
extra={"preserve_color": True},
|
||||
)
|
||||
|
||||
# Print the ai_profile details
|
||||
print_attribute("Name :", ai_profile.ai_name)
|
||||
print_attribute("Role :", ai_profile.ai_role)
|
||||
print_attribute("Goals:", "")
|
||||
for goal in ai_profile.ai_goals:
|
||||
logger.info(f"- {goal}")
|
||||
|
||||
return ai_profile
|
||||
|
||||
|
||||
def print_assistant_thoughts(
|
||||
ai_name: str,
|
||||
assistant_reply_json_valid: dict,
|
||||
|
||||
@@ -1,253 +1,190 @@
|
||||
"""Set up the AI and its goals"""
|
||||
import logging
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
from colorama import Fore, Style
|
||||
from jinja2 import Template
|
||||
|
||||
from autogpt.app import utils
|
||||
from autogpt.config import Config
|
||||
from autogpt.config.ai_profile import AIProfile
|
||||
from autogpt.core.resource.model_providers import ChatMessage, ChatModelProvider
|
||||
from autogpt.logs.helpers import user_friendly_output
|
||||
from autogpt.prompts.default_prompts import (
|
||||
DEFAULT_SYSTEM_PROMPT_AICONFIG_AUTOMATIC,
|
||||
DEFAULT_TASK_PROMPT_AICONFIG_AUTOMATIC,
|
||||
DEFAULT_USER_DESIRE_PROMPT,
|
||||
)
|
||||
from autogpt.app.utils import clean_input
|
||||
from autogpt.config import AIProfile, AIDirectives, Config
|
||||
from autogpt.logs.helpers import print_attribute
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def interactive_ai_profile_setup(
|
||||
config: Config,
|
||||
llm_provider: ChatModelProvider,
|
||||
ai_profile_template: Optional[AIProfile] = None,
|
||||
) -> AIProfile:
|
||||
"""Prompt the user for input
|
||||
def apply_overrides_to_ai_settings(
|
||||
ai_profile: AIProfile,
|
||||
directives: AIDirectives,
|
||||
override_name: str = "",
|
||||
override_role: str = "",
|
||||
replace_directives: bool = False,
|
||||
resources: Optional[list[str]] = None,
|
||||
constraints: Optional[list[str]] = None,
|
||||
best_practices: Optional[list[str]] = None,
|
||||
):
|
||||
if override_name:
|
||||
ai_profile.ai_name = override_name
|
||||
if override_role:
|
||||
ai_profile.ai_role = override_role
|
||||
|
||||
Params:
|
||||
config (Config): The Config object
|
||||
ai_profile_template (AIProfile): The AIProfile object to use as a template
|
||||
if replace_directives:
|
||||
if resources:
|
||||
directives.resources = resources
|
||||
if constraints:
|
||||
directives.constraints = constraints
|
||||
if best_practices:
|
||||
directives.best_practices = best_practices
|
||||
else:
|
||||
if resources:
|
||||
directives.resources += resources
|
||||
if constraints:
|
||||
directives.constraints += constraints
|
||||
if best_practices:
|
||||
directives.best_practices += best_practices
|
||||
|
||||
|
||||
async def interactively_revise_ai_settings(
|
||||
ai_profile: AIProfile,
|
||||
directives: AIDirectives,
|
||||
app_config: Config,
|
||||
):
|
||||
"""Interactively revise the AI settings.
|
||||
|
||||
Args:
|
||||
ai_profile (AIConfig): The current AI profile.
|
||||
ai_directives (AIDirectives): The current AI directives.
|
||||
app_config (Config): The application configuration.
|
||||
|
||||
Returns:
|
||||
AIProfile: The AIProfile object tailored to the user's input
|
||||
AIConfig: The revised AI settings.
|
||||
"""
|
||||
logger = logging.getLogger("revise_ai_profile")
|
||||
|
||||
# Construct the prompt
|
||||
user_friendly_output(
|
||||
title="Welcome to AutoGPT! ",
|
||||
message="run with '--help' for more information.",
|
||||
title_color=Fore.GREEN,
|
||||
)
|
||||
revised = False
|
||||
|
||||
ai_profile_template_provided = ai_profile_template is not None and any(
|
||||
[
|
||||
ai_profile_template.ai_goals,
|
||||
ai_profile_template.ai_name,
|
||||
ai_profile_template.ai_role,
|
||||
]
|
||||
)
|
||||
|
||||
user_desire = ""
|
||||
if not ai_profile_template_provided:
|
||||
# Get user desire if command line overrides have not been passed in
|
||||
user_friendly_output(
|
||||
title="Create an AI-Assistant:",
|
||||
message="input '--manual' to enter manual mode.",
|
||||
title_color=Fore.GREEN,
|
||||
while True:
|
||||
# Print the current AI configuration
|
||||
print_ai_settings(
|
||||
title="Current AI Settings" if not revised else "Revised AI Settings",
|
||||
ai_profile=ai_profile,
|
||||
directives=directives,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
user_desire = await utils.clean_input(
|
||||
config, f"{Fore.LIGHTBLUE_EX}I want AutoGPT to{Style.RESET_ALL}: "
|
||||
)
|
||||
if (
|
||||
await clean_input(app_config, "Continue with these settings? [Y/n]")
|
||||
or app_config.authorise_key
|
||||
) == app_config.authorise_key:
|
||||
break
|
||||
|
||||
if user_desire.strip() == "":
|
||||
user_desire = DEFAULT_USER_DESIRE_PROMPT # Default prompt
|
||||
|
||||
# If user desire contains "--manual" or we have overridden any of the AI configuration
|
||||
if "--manual" in user_desire or ai_profile_template_provided:
|
||||
user_friendly_output(
|
||||
"",
|
||||
title="Manual Mode Selected",
|
||||
title_color=Fore.GREEN,
|
||||
)
|
||||
return await generate_aiconfig_manual(config, ai_profile_template)
|
||||
|
||||
else:
|
||||
try:
|
||||
return await generate_aiconfig_automatic(user_desire, config, llm_provider)
|
||||
except Exception as e:
|
||||
user_friendly_output(
|
||||
title="Unable to automatically generate AI Config based on user desire.",
|
||||
message="Falling back to manual mode.",
|
||||
title_color=Fore.RED,
|
||||
# Ask for revised ai_profile
|
||||
ai_profile.ai_name = (
|
||||
await clean_input(
|
||||
app_config, "Enter AI name (or press enter to keep current):"
|
||||
)
|
||||
logger.debug(f"Error during AIProfile generation: {e}")
|
||||
|
||||
return await generate_aiconfig_manual(config)
|
||||
|
||||
|
||||
async def generate_aiconfig_manual(
|
||||
config: Config, ai_profile_template: Optional[AIProfile] = None
|
||||
) -> AIProfile:
|
||||
"""
|
||||
Interactively create an AI configuration by prompting the user to provide the name, role, and goals of the AI.
|
||||
|
||||
This function guides the user through a series of prompts to collect the necessary information to create
|
||||
an AIProfile object. The user will be asked to provide a name and role for the AI, as well as up to five
|
||||
goals. If the user does not provide a value for any of the fields, default values will be used.
|
||||
|
||||
Params:
|
||||
config (Config): The Config object
|
||||
ai_profile_template (AIProfile): The AIProfile object to use as a template
|
||||
|
||||
Returns:
|
||||
AIProfile: An AIProfile object containing the user-defined or default AI name, role, and goals.
|
||||
"""
|
||||
|
||||
# Manual Setup Intro
|
||||
user_friendly_output(
|
||||
title="Create an AI-Assistant:",
|
||||
message="Enter the name of your AI and its role below. Entering nothing will load"
|
||||
" defaults.",
|
||||
title_color=Fore.GREEN,
|
||||
)
|
||||
|
||||
if ai_profile_template and ai_profile_template.ai_name:
|
||||
ai_name = ai_profile_template.ai_name
|
||||
else:
|
||||
ai_name = ""
|
||||
# Get AI Name from User
|
||||
user_friendly_output(
|
||||
title="Name your AI:",
|
||||
message="For example, 'Entrepreneur-GPT'",
|
||||
title_color=Fore.GREEN,
|
||||
or ai_profile.ai_name
|
||||
)
|
||||
ai_name = await utils.clean_input(config, "AI Name: ")
|
||||
if ai_name == "":
|
||||
ai_name = "Entrepreneur-GPT"
|
||||
|
||||
user_friendly_output(
|
||||
title=f"{ai_name} here!",
|
||||
message="I am at your service.",
|
||||
title_color=Fore.LIGHTBLUE_EX,
|
||||
)
|
||||
|
||||
if ai_profile_template and ai_profile_template.ai_role:
|
||||
ai_role = ai_profile_template.ai_role
|
||||
else:
|
||||
# Get AI Role from User
|
||||
user_friendly_output(
|
||||
title="Describe your AI's role:",
|
||||
message="For example, 'an AI designed to autonomously develop and run businesses with"
|
||||
" the sole goal of increasing your net worth.'",
|
||||
title_color=Fore.GREEN,
|
||||
)
|
||||
ai_role = await utils.clean_input(config, f"{ai_name} is: ")
|
||||
if ai_role == "":
|
||||
ai_role = "an AI designed to autonomously develop and run businesses with the"
|
||||
" sole goal of increasing your net worth."
|
||||
|
||||
if ai_profile_template and ai_profile_template.ai_goals:
|
||||
ai_goals = ai_profile_template.ai_goals
|
||||
else:
|
||||
# Enter up to 5 goals for the AI
|
||||
user_friendly_output(
|
||||
title="Enter up to 5 goals for your AI:",
|
||||
message="For example: \nIncrease net worth, Grow Twitter Account, Develop and manage"
|
||||
" multiple businesses autonomously'",
|
||||
title_color=Fore.GREEN,
|
||||
)
|
||||
logger.info("Enter nothing to load defaults, enter nothing when finished.")
|
||||
ai_goals = []
|
||||
for i in range(5):
|
||||
ai_goal = await utils.clean_input(
|
||||
config, f"{Fore.LIGHTBLUE_EX}Goal{Style.RESET_ALL} {i+1}: "
|
||||
ai_profile.ai_role = (
|
||||
await clean_input(
|
||||
app_config, "Enter new AI role (or press enter to keep current):"
|
||||
)
|
||||
if ai_goal == "":
|
||||
or ai_profile.ai_role
|
||||
)
|
||||
|
||||
# Revise constraints
|
||||
for i, constraint in enumerate(directives.constraints):
|
||||
print_attribute(f"Constraint {i+1}:", f'"{constraint}"')
|
||||
new_constraint = (
|
||||
await clean_input(
|
||||
app_config,
|
||||
f"Enter new constraint {i+1} (press enter to keep current, or '-' to remove):",
|
||||
)
|
||||
or constraint
|
||||
)
|
||||
if new_constraint == "-":
|
||||
directives.constraints.remove(constraint)
|
||||
elif new_constraint:
|
||||
directives.constraints[i] = new_constraint
|
||||
|
||||
# Add new constraints
|
||||
while True:
|
||||
new_constraint = await clean_input(
|
||||
app_config,
|
||||
"Press enter to finish, or enter a constraint to add:",
|
||||
)
|
||||
if not new_constraint:
|
||||
break
|
||||
ai_goals.append(ai_goal)
|
||||
if not ai_goals:
|
||||
ai_goals = [
|
||||
"Increase net worth",
|
||||
"Grow Twitter Account",
|
||||
"Develop and manage multiple businesses autonomously",
|
||||
]
|
||||
directives.constraints.append(new_constraint)
|
||||
|
||||
# Get API Budget from User
|
||||
user_friendly_output(
|
||||
title="Enter your budget for API calls:",
|
||||
message="For example: $1.50",
|
||||
title_color=Fore.GREEN,
|
||||
)
|
||||
logger.info("Enter nothing to let the AI run without monetary limit")
|
||||
api_budget_input = await utils.clean_input(
|
||||
config, f"{Fore.LIGHTBLUE_EX}Budget{Style.RESET_ALL}: $"
|
||||
)
|
||||
if api_budget_input == "":
|
||||
api_budget = 0.0
|
||||
else:
|
||||
try:
|
||||
api_budget = float(api_budget_input.replace("$", ""))
|
||||
except ValueError:
|
||||
user_friendly_output(
|
||||
level=logging.WARNING,
|
||||
title="Invalid budget input.",
|
||||
message="Setting budget to unlimited.",
|
||||
title_color=Fore.RED,
|
||||
# Revise resources
|
||||
for i, resource in enumerate(directives.resources):
|
||||
print_attribute(f"Resource {i+1}:", f'"{resource}"')
|
||||
new_resource = (
|
||||
await clean_input(
|
||||
app_config,
|
||||
f"Enter new resource {i+1} (press enter to keep current, or '-' to remove):",
|
||||
)
|
||||
or resource
|
||||
)
|
||||
api_budget = 0.0
|
||||
if new_resource == "-":
|
||||
directives.resources.remove(resource)
|
||||
elif new_resource:
|
||||
directives.resources[i] = new_resource
|
||||
|
||||
return AIProfile(
|
||||
ai_name=ai_name, ai_role=ai_role, ai_goals=ai_goals, api_budget=api_budget
|
||||
)
|
||||
# Add new resources
|
||||
while True:
|
||||
new_resource = await clean_input(
|
||||
app_config,
|
||||
"Press enter to finish, or enter a resource to add:",
|
||||
)
|
||||
if not new_resource:
|
||||
break
|
||||
directives.resources.append(new_resource)
|
||||
|
||||
# Revise best practices
|
||||
for i, best_practice in enumerate(directives.best_practices):
|
||||
print_attribute(f"Best Practice {i+1}:", f'"{best_practice}"')
|
||||
new_best_practice = (
|
||||
await clean_input(
|
||||
app_config,
|
||||
f"Enter new best practice {i+1} (press enter to keep current, or '-' to remove):",
|
||||
)
|
||||
or best_practice
|
||||
)
|
||||
if new_best_practice == "-":
|
||||
directives.best_practices.remove(best_practice)
|
||||
elif new_best_practice:
|
||||
directives.best_practices[i] = new_best_practice
|
||||
|
||||
# Add new best practices
|
||||
while True:
|
||||
new_best_practice = await clean_input(
|
||||
app_config,
|
||||
"Press enter to finish, or add a best practice to add:",
|
||||
)
|
||||
if not new_best_practice:
|
||||
break
|
||||
directives.best_practices.append(new_best_practice)
|
||||
|
||||
revised = True
|
||||
|
||||
return ai_profile, directives
|
||||
|
||||
|
||||
async def generate_aiconfig_automatic(
|
||||
user_prompt: str,
|
||||
config: Config,
|
||||
llm_provider: ChatModelProvider,
|
||||
) -> AIProfile:
|
||||
"""Generates an AIProfile object from the given string.
|
||||
def print_ai_settings(
|
||||
ai_profile: AIProfile,
|
||||
directives: AIDirectives,
|
||||
logger: logging.Logger,
|
||||
title: str = "AI Settings",
|
||||
):
|
||||
print_attribute(title, "")
|
||||
print_attribute("-" * len(title), "")
|
||||
print_attribute("Name :", ai_profile.ai_name)
|
||||
print_attribute("Role :", ai_profile.ai_role)
|
||||
|
||||
Returns:
|
||||
AIProfile: The AIProfile object tailored to the user's input
|
||||
"""
|
||||
|
||||
system_prompt = DEFAULT_SYSTEM_PROMPT_AICONFIG_AUTOMATIC
|
||||
prompt_ai_profile_automatic = Template(
|
||||
DEFAULT_TASK_PROMPT_AICONFIG_AUTOMATIC
|
||||
).render(user_prompt=user_prompt)
|
||||
# Call LLM with the string as user input
|
||||
output = (
|
||||
await llm_provider.create_chat_completion(
|
||||
[
|
||||
ChatMessage.system(system_prompt),
|
||||
ChatMessage.user(prompt_ai_profile_automatic),
|
||||
],
|
||||
config.smart_llm,
|
||||
)
|
||||
).response["content"]
|
||||
|
||||
# Debug LLM Output
|
||||
logger.debug(f"AI Config Generator Raw Output: {output}")
|
||||
|
||||
# Parse the output
|
||||
ai_name = re.search(r"Name(?:\s*):(?:\s*)(.*)", output, re.IGNORECASE).group(1)
|
||||
ai_role = (
|
||||
re.search(
|
||||
r"Description(?:\s*):(?:\s*)(.*?)(?:(?:\n)|Goals)",
|
||||
output,
|
||||
re.IGNORECASE | re.DOTALL,
|
||||
)
|
||||
.group(1)
|
||||
.strip()
|
||||
)
|
||||
ai_goals = re.findall(r"(?<=\n)-\s*(.*)", output)
|
||||
api_budget = 0.0 # TODO: parse api budget using a regular expression
|
||||
|
||||
return AIProfile(
|
||||
ai_name=ai_name, ai_role=ai_role, ai_goals=ai_goals, api_budget=api_budget
|
||||
)
|
||||
print_attribute("Constraints:", "" if directives.constraints else "(none)")
|
||||
for constraint in directives.constraints:
|
||||
logger.info(f"- {constraint}")
|
||||
print_attribute("Resources:", "" if directives.resources else "(none)")
|
||||
for resource in directives.resources:
|
||||
logger.info(f"- {resource}")
|
||||
print_attribute("Best practices:", "" if directives.best_practices else "(none)")
|
||||
for best_practice in directives.best_practices:
|
||||
logger.info(f"- {best_practice}")
|
||||
|
||||
@@ -39,3 +39,10 @@ class AIDirectives(BaseModel):
|
||||
resources=config_params.get("resources", []),
|
||||
best_practices=config_params.get("best_practices", []),
|
||||
)
|
||||
|
||||
def __add__(self, other: "AIDirectives") -> "AIDirectives":
|
||||
return AIDirectives(
|
||||
resources=self.resources + other.resources,
|
||||
constraints=self.constraints + other.constraints,
|
||||
best_practices=self.best_practices + other.best_practices,
|
||||
).copy(deep=True)
|
||||
|
||||
@@ -2,78 +2,49 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from autogpt.app.setup import generate_aiconfig_automatic, interactive_ai_profile_setup
|
||||
from autogpt.app.setup import (
|
||||
apply_overrides_to_ai_settings,
|
||||
interactively_revise_ai_settings,
|
||||
)
|
||||
from autogpt.config.ai_profile import AIProfile
|
||||
from autogpt.config import AIDirectives, Config
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.requires_openai_api_key
|
||||
async def test_generate_aiconfig_automatic_default(
|
||||
patched_api_requestor, config, llm_provider
|
||||
):
|
||||
user_inputs = [""]
|
||||
with patch("autogpt.app.utils.session.prompt", side_effect=user_inputs):
|
||||
ai_profile = await interactive_ai_profile_setup(config, llm_provider)
|
||||
@pytest.mark.asyncio
|
||||
async def test_apply_overrides_to_ai_settings():
|
||||
ai_profile = AIProfile(ai_name="Test AI", ai_role="Test Role")
|
||||
directives = AIDirectives(resources=["Resource1"], constraints=["Constraint1"], best_practices=["BestPractice1"])
|
||||
|
||||
assert isinstance(ai_profile, AIProfile)
|
||||
assert ai_profile.ai_name is not None
|
||||
assert ai_profile.ai_role is not None
|
||||
assert 1 <= len(ai_profile.ai_goals) <= 5
|
||||
apply_overrides_to_ai_settings(ai_profile, directives, override_name="New AI", override_role="New Role", replace_directives=True, resources=["NewResource"], constraints=["NewConstraint"], best_practices=["NewBestPractice"])
|
||||
|
||||
assert ai_profile.ai_name == "New AI"
|
||||
assert ai_profile.ai_role == "New Role"
|
||||
assert directives.resources == ["NewResource"]
|
||||
assert directives.constraints == ["NewConstraint"]
|
||||
assert directives.best_practices == ["NewBestPractice"]
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.requires_openai_api_key
|
||||
async def test_generate_aiconfig_automatic_typical(
|
||||
patched_api_requestor, config, llm_provider
|
||||
):
|
||||
user_prompt = "Help me create a rock opera about cybernetic giraffes"
|
||||
ai_profile = await generate_aiconfig_automatic(user_prompt, config, llm_provider)
|
||||
@pytest.mark.asyncio
|
||||
async def test_interactively_revise_ai_settings(config: Config):
|
||||
ai_profile = AIProfile(ai_name="Test AI", ai_role="Test Role")
|
||||
directives = AIDirectives(resources=["Resource1"], constraints=["Constraint1"], best_practices=["BestPractice1"])
|
||||
|
||||
assert isinstance(ai_profile, AIProfile)
|
||||
assert ai_profile.ai_name is not None
|
||||
assert ai_profile.ai_role is not None
|
||||
assert 1 <= len(ai_profile.ai_goals) <= 5
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.requires_openai_api_key
|
||||
async def test_generate_aiconfig_automatic_fallback(
|
||||
patched_api_requestor, config, llm_provider
|
||||
):
|
||||
user_inputs = [
|
||||
"T&GF£OIBECC()!*",
|
||||
"Chef-GPT",
|
||||
"an AI designed to browse bake a cake.",
|
||||
"Purchase ingredients",
|
||||
"Bake a cake",
|
||||
"y",
|
||||
"New AI",
|
||||
"New Role",
|
||||
"NewConstraint",
|
||||
"",
|
||||
"NewResource",
|
||||
"",
|
||||
"NewBestPractice",
|
||||
"",
|
||||
]
|
||||
with patch("autogpt.app.utils.session.prompt", side_effect=user_inputs):
|
||||
ai_profile = await interactive_ai_profile_setup(config, llm_provider)
|
||||
with patch("autogpt.app.utils.clean_input", side_effect=user_inputs):
|
||||
ai_profile, directives = await interactively_revise_ai_settings(ai_profile, directives, config)
|
||||
|
||||
assert isinstance(ai_profile, AIProfile)
|
||||
assert ai_profile.ai_name == "Chef-GPT"
|
||||
assert ai_profile.ai_role == "an AI designed to browse bake a cake."
|
||||
assert ai_profile.ai_goals == ["Purchase ingredients", "Bake a cake"]
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.requires_openai_api_key
|
||||
async def test_prompt_user_manual_mode(patched_api_requestor, config, llm_provider):
|
||||
user_inputs = [
|
||||
"--manual",
|
||||
"Chef-GPT",
|
||||
"an AI designed to browse bake a cake.",
|
||||
"Purchase ingredients",
|
||||
"Bake a cake",
|
||||
"",
|
||||
"",
|
||||
]
|
||||
with patch("autogpt.app.utils.session.prompt", side_effect=user_inputs):
|
||||
ai_profile = await interactive_ai_profile_setup(config, llm_provider)
|
||||
|
||||
assert isinstance(ai_profile, AIProfile)
|
||||
assert ai_profile.ai_name == "Chef-GPT"
|
||||
assert ai_profile.ai_role == "an AI designed to browse bake a cake."
|
||||
assert ai_profile.ai_goals == ["Purchase ingredients", "Bake a cake"]
|
||||
assert ai_profile.ai_name == "New AI"
|
||||
assert ai_profile.ai_role == "New Role"
|
||||
assert directives.resources == ["NewResource"]
|
||||
assert directives.constraints == ["NewConstraint"]
|
||||
assert directives.best_practices == ["NewBestPractice"]
|
||||
|
||||
Reference in New Issue
Block a user