resolving test failures

This commit is contained in:
Peter
2023-04-06 19:25:44 -07:00
parent e2a6ed6955
commit b4a0ef9bab
9 changed files with 58 additions and 83 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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}'

View File

@@ -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"

View File

@@ -1,6 +1,5 @@
import browse
import json
from memory import PineconeMemory
import datetime
import agent_manager as agents
import speak