mirror of
https://github.com/aljazceru/Auto-GPT.git
synced 2026-01-03 22:34:29 +01:00
resolving test failures
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
from typing import List, Optional
|
||||
from typing import List
|
||||
import json
|
||||
from config import Config
|
||||
from call_ai_function import call_ai_function
|
||||
from json_parser import fix_and_parse_json
|
||||
from auto_gpt.commands import command
|
||||
|
||||
cfg = Config()
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import importlib
|
||||
import inspect
|
||||
from typing import Callable, Any, List
|
||||
|
||||
# Unique identifier for auto-gpt commands
|
||||
AUTO_GPT_COMMAND_IDENTIFIER = "auto_gpt_command"
|
||||
|
||||
class Command:
|
||||
"""A class representing a command.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the command.
|
||||
description (str): A brief description of what the command does.
|
||||
method (Callable[..., Any]): The function that the command executes.
|
||||
signature (str): The signature of the function that the command executes. Defaults to None.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, description: str, method: Callable[..., Any], signature: str = None):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.method = method
|
||||
self.signature = signature if signature else str(inspect.signature(self.method))
|
||||
|
||||
def __call__(self, *args, **kwargs) -> Any:
|
||||
return self.method(*args, **kwargs)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.name}: {self.description}, args: {self.signature}"
|
||||
|
||||
class CommandRegistry:
|
||||
"""
|
||||
The CommandRegistry class is a manager for a collection of Command objects.
|
||||
It allows the registration, modification, and retrieval of Command objects,
|
||||
as well as the scanning and loading of command plugins from a specified
|
||||
directory.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.commands = {}
|
||||
|
||||
def _import_module(self, module_name: str) -> Any:
|
||||
return importlib.import_module(module_name)
|
||||
|
||||
def _reload_module(self, module: Any) -> Any:
|
||||
return importlib.reload(module)
|
||||
|
||||
def register_command(self, cmd: Command) -> None:
|
||||
self.commands[cmd.name] = cmd
|
||||
|
||||
def reload_commands(self) -> None:
|
||||
"""Reloads all loaded command plugins."""
|
||||
for cmd_name in self.commands:
|
||||
cmd = self.commands[cmd_name]
|
||||
module = self._import_module(cmd.__module__)
|
||||
reloaded_module = self._reload_module(module)
|
||||
if hasattr(reloaded_module, "register"):
|
||||
reloaded_module.register(self)
|
||||
|
||||
def get_command(self, name: str) -> Callable[..., Any]:
|
||||
return self.commands.get(name)
|
||||
|
||||
def list_commands(self) -> List[str]:
|
||||
return [str(cmd) for cmd in self.commands.values()]
|
||||
|
||||
def command_prompt(self) -> str:
|
||||
"""
|
||||
Returns a string representation of all registered `Command` objects for use in a prompt
|
||||
"""
|
||||
commands_list = [f"{idx + 1}. {str(cmd)}" for idx, cmd in enumerate(self.commands.values())]
|
||||
return "\n".join(commands_list)
|
||||
|
||||
def scan_directory_for_plugins(self, directory: str) -> None:
|
||||
"""
|
||||
Scans the specified directory for Python files containing command plugins.
|
||||
|
||||
For each file in the directory that ends with ".py", this method imports the associated module and registers any
|
||||
functions or classes that are decorated with the `AUTO_GPT_COMMAND_IDENTIFIER` attribute as `Command` objects.
|
||||
The registered `Command` objects are then added to the `commands` dictionary of the `CommandRegistry` object.
|
||||
|
||||
Args:
|
||||
directory (str): The directory to scan for command plugins.
|
||||
"""
|
||||
|
||||
for file in os.listdir(directory):
|
||||
if file.endswith(".py"):
|
||||
module_name = file[:-3]
|
||||
module = importlib.import_module(module_name)
|
||||
for attr_name in dir(module):
|
||||
attr = getattr(module, attr_name)
|
||||
# Register decorated functions
|
||||
if hasattr(attr, AUTO_GPT_COMMAND_IDENTIFIER) and getattr(attr, AUTO_GPT_COMMAND_IDENTIFIER):
|
||||
self.register_command(attr.register_command)
|
||||
# Register command classes
|
||||
elif inspect.isclass(attr) and issubclass(attr, Command) and attr != Command:
|
||||
cmd_instance = attr()
|
||||
self.register_command(cmd_instance)
|
||||
|
||||
|
||||
def command(name: str, description: str, signature: str = None) -> Callable[..., Any]:
|
||||
"""The command decorator is used to create Command objects from ordinary functions."""
|
||||
def decorator(func: Callable[..., Any]) -> Command:
|
||||
cmd = Command(name=name, description=description, method=func, signature=signature)
|
||||
|
||||
def wrapper(*args, **kwargs) -> Any:
|
||||
return func(*args, **kwargs)
|
||||
|
||||
wrapper.register_command = cmd
|
||||
setattr(wrapper, AUTO_GPT_COMMAND_IDENTIFIER, True)
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
from commands import Command, command
|
||||
|
||||
class TestCommand(Command):
|
||||
def __init__(self):
|
||||
super().__init__(name='class_based', description='Class-based test command')
|
||||
|
||||
def __call__(self, arg1: int, arg2: str) -> str:
|
||||
return f'{arg1} - {arg2}'
|
||||
|
||||
@command('function_based', 'Function-based test command')
|
||||
def function_based(arg1: int, arg2: str) -> str:
|
||||
return f'{arg1} - {arg2}'
|
||||
@@ -1,174 +0,0 @@
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from commands import Command, CommandRegistry
|
||||
|
||||
|
||||
class TestCommand:
|
||||
@staticmethod
|
||||
def example_function(arg1: int, arg2: str) -> str:
|
||||
return f"{arg1} - {arg2}"
|
||||
|
||||
def test_command_creation(self):
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
assert cmd.name == "example"
|
||||
assert cmd.description == "Example command"
|
||||
assert cmd.method == self.example_function
|
||||
assert cmd.signature == "arg1: int, arg2: str"
|
||||
|
||||
def test_command_call(self):
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
result = cmd(arg1=1, arg2="test")
|
||||
assert result == "1 - test"
|
||||
|
||||
def test_command_call_with_invalid_arguments(self):
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
cmd(arg1="invalid", arg2="test")
|
||||
|
||||
def test_command_default_signature(self):
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
assert cmd.signature == "arg1: int, arg2: str"
|
||||
|
||||
def test_command_custom_signature(self):
|
||||
custom_signature = "custom_arg1: int, custom_arg2: str"
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function, signature=custom_signature)
|
||||
|
||||
assert cmd.signature == custom_signature
|
||||
|
||||
|
||||
|
||||
class TestCommandRegistry:
|
||||
@staticmethod
|
||||
def example_function(arg1: int, arg2: str) -> str:
|
||||
return f"{arg1} - {arg2}"
|
||||
|
||||
def test_register_command(self):
|
||||
"""Test that a command can be registered to the registry."""
|
||||
registry = CommandRegistry()
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
registry.register(cmd)
|
||||
|
||||
assert cmd.name in registry._commands
|
||||
assert registry._commands[cmd.name] == cmd
|
||||
|
||||
def test_unregister_command(self):
|
||||
"""Test that a command can be unregistered from the registry."""
|
||||
registry = CommandRegistry()
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
registry.register(cmd)
|
||||
registry.unregister(cmd.name)
|
||||
|
||||
assert cmd.name not in registry._commands
|
||||
|
||||
def test_get_command(self):
|
||||
"""Test that a command can be retrieved from the registry."""
|
||||
registry = CommandRegistry()
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
registry.register(cmd)
|
||||
retrieved_cmd = registry.get(cmd.name)
|
||||
|
||||
assert retrieved_cmd == cmd
|
||||
|
||||
def test_get_nonexistent_command(self):
|
||||
"""Test that attempting to get a nonexistent command raises a KeyError."""
|
||||
registry = CommandRegistry()
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
registry.get("nonexistent_command")
|
||||
|
||||
def test_call_command(self):
|
||||
"""Test that a command can be called through the registry."""
|
||||
registry = CommandRegistry()
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
registry.register(cmd)
|
||||
result = registry.call("example", arg1=1, arg2="test")
|
||||
|
||||
assert result == "1 - test"
|
||||
|
||||
def test_call_nonexistent_command(self):
|
||||
"""Test that attempting to call a nonexistent command raises a KeyError."""
|
||||
registry = CommandRegistry()
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
registry.call("nonexistent_command", arg1=1, arg2="test")
|
||||
|
||||
def test_get_command_list(self):
|
||||
"""Test that a list of registered commands can be retrieved."""
|
||||
registry = CommandRegistry()
|
||||
cmd1 = Command(name="example1", description="Example command 1", method=self.example_function)
|
||||
cmd2 = Command(name="example2", description="Example command 2", method=self.example_function)
|
||||
|
||||
registry.register(cmd1)
|
||||
registry.register(cmd2)
|
||||
command_list = registry.get_command_list()
|
||||
|
||||
assert len(command_list) == 2
|
||||
assert cmd1.name in command_list
|
||||
assert cmd2.name in command_list
|
||||
|
||||
def test_get_command_prompt(self):
|
||||
"""Test that the command prompt is correctly formatted."""
|
||||
registry = CommandRegistry()
|
||||
cmd = Command(name="example", description="Example command", method=self.example_function)
|
||||
|
||||
registry.register(cmd)
|
||||
command_prompt = registry.get_command_prompt()
|
||||
|
||||
assert f"{cmd.name}: {cmd.description}, args: {cmd.signature}" in command_prompt
|
||||
|
||||
def test_scan_directory_for_mock_commands(self):
|
||||
"""Test that the registry can scan a directory for mock command plugins."""
|
||||
registry = CommandRegistry()
|
||||
mock_commands_dir = Path("auto_gpt/tests/mocks")
|
||||
|
||||
registry.scan_directory_for_plugins(mock_commands_dir)
|
||||
|
||||
assert "mock_class_based" in registry._commands
|
||||
assert registry._commands["mock_class_based"].name == "mock_class_based"
|
||||
assert registry._commands["mock_class_based"].description == "Mock class-based command"
|
||||
|
||||
assert "mock_function_based" in registry._commands
|
||||
assert registry._commands["mock_function_based"].name == "mock_function_based"
|
||||
assert registry._commands["mock_function_based"].description == "Mock function-based command"
|
||||
|
||||
def test_scan_directory_for_temp_command_file(self, tmp_path):
|
||||
"""Test that the registry can scan a directory for command plugins in a temp file."""
|
||||
registry = CommandRegistry()
|
||||
temp_commands_dir = tmp_path / "temp_commands"
|
||||
temp_commands_dir.mkdir()
|
||||
|
||||
# Create a temp command file
|
||||
temp_commands_file = temp_commands_dir / "temp_commands.py"
|
||||
temp_commands_content = (
|
||||
"from commands import Command, command\n\n"
|
||||
"class TempCommand(Command):\n"
|
||||
" def __init__(self):\n"
|
||||
" super().__init__(name='temp_class_based', description='Temp class-based command')\n\n"
|
||||
" def __call__(self, arg1: int, arg2: str) -> str:\n"
|
||||
" return f'{arg1} - {arg2}'\n\n"
|
||||
"@command('temp_function_based', 'Temp function-based command')\n"
|
||||
"def temp_function_based(arg1: int, arg2: str) -> str:\n"
|
||||
" return f'{arg1} - {arg2}'\n"
|
||||
)
|
||||
|
||||
with open(temp_commands_file, "w") as f:
|
||||
f.write(temp_commands_content)
|
||||
|
||||
registry.scan_directory_for_plugins(temp_commands_dir)
|
||||
|
||||
assert "temp_class_based" in registry._commands
|
||||
assert registry._commands["temp_class_based"].name == "temp_class_based"
|
||||
assert registry._commands["temp_class_based"].description == "Temp class-based command"
|
||||
|
||||
assert "temp_function_based" in registry._commands
|
||||
assert registry._commands["temp_function_based"].name == "temp_function_based"
|
||||
assert registry._commands["temp_function_based"].description == "Temp function-based command"
|
||||
@@ -1,6 +1,5 @@
|
||||
import browse
|
||||
import json
|
||||
from memory import PineconeMemory
|
||||
import datetime
|
||||
import agent_manager as agents
|
||||
import speak
|
||||
|
||||
Reference in New Issue
Block a user