mirror of
https://github.com/aljazceru/Auto-GPT.git
synced 2026-01-14 19:44:22 +01:00
Rename Workspace -> FileWorkspace; expand interface
This commit is contained in:
@@ -38,8 +38,8 @@ from autogpt.models.context_item import ContextItem
|
||||
|
||||
from .base import BaseAgent, BaseAgentConfiguration, BaseAgentSettings
|
||||
from .features.context import ContextMixin
|
||||
from .features.file_workspace import FileWorkspaceMixin
|
||||
from .features.watchdog import WatchdogMixin
|
||||
from .features.workspace import WorkspaceMixin
|
||||
from .prompt_strategies.one_shot import (
|
||||
OneShotAgentPromptConfiguration,
|
||||
OneShotAgentPromptStrategy,
|
||||
@@ -64,7 +64,7 @@ class AgentSettings(BaseAgentSettings):
|
||||
|
||||
class Agent(
|
||||
ContextMixin,
|
||||
WorkspaceMixin,
|
||||
FileWorkspaceMixin,
|
||||
WatchdogMixin,
|
||||
BaseAgent,
|
||||
Configurable[AgentSettings],
|
||||
|
||||
@@ -7,20 +7,20 @@ if TYPE_CHECKING:
|
||||
|
||||
from ..base import BaseAgent
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
|
||||
from ..base import AgentFileManager, BaseAgentConfiguration
|
||||
|
||||
|
||||
class WorkspaceMixin:
|
||||
class FileWorkspaceMixin:
|
||||
"""Mixin that adds workspace support to a class"""
|
||||
|
||||
workspace: Workspace | None
|
||||
workspace: FileWorkspace = None
|
||||
"""Workspace that the agent has access to, e.g. for reading/writing files."""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# Initialize other bases first, because we need the config from BaseAgent
|
||||
super(WorkspaceMixin, self).__init__(**kwargs)
|
||||
super(FileWorkspaceMixin, self).__init__(**kwargs)
|
||||
|
||||
config: BaseAgentConfiguration = getattr(self, "config")
|
||||
if not isinstance(config, BaseAgentConfiguration):
|
||||
@@ -34,7 +34,7 @@ class WorkspaceMixin:
|
||||
self.workspace = _setup_workspace(file_manager, config)
|
||||
|
||||
def attach_fs(self, agent_dir: Path):
|
||||
res = super(WorkspaceMixin, self).attach_fs(agent_dir)
|
||||
res = super(FileWorkspaceMixin, self).attach_fs(agent_dir)
|
||||
|
||||
self.workspace = _setup_workspace(self.file_manager, self.config)
|
||||
|
||||
@@ -42,16 +42,16 @@ class WorkspaceMixin:
|
||||
|
||||
|
||||
def _setup_workspace(file_manager: AgentFileManager, config: BaseAgentConfiguration):
|
||||
workspace = Workspace(
|
||||
workspace = FileWorkspace(
|
||||
file_manager.root / "workspace",
|
||||
restrict_to_workspace=not config.allow_fs_access,
|
||||
restrict_to_root=not config.allow_fs_access,
|
||||
)
|
||||
workspace.initialize()
|
||||
return workspace
|
||||
|
||||
|
||||
def get_agent_workspace(agent: BaseAgent) -> Workspace | None:
|
||||
if isinstance(agent, WorkspaceMixin):
|
||||
def get_agent_workspace(agent: BaseAgent) -> FileWorkspace | None:
|
||||
if isinstance(agent, FileWorkspaceMixin):
|
||||
return agent.workspace
|
||||
|
||||
return None
|
||||
@@ -32,12 +32,12 @@ from autogpt.models.context_item import ContextItem
|
||||
from .agent import execute_command, extract_command
|
||||
from .base import BaseAgent
|
||||
from .features.context import ContextMixin
|
||||
from .features.workspace import WorkspaceMixin
|
||||
from .features.file_workspace import FileWorkspaceMixin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PlanningAgent(ContextMixin, WorkspaceMixin, BaseAgent):
|
||||
class PlanningAgent(ContextMixin, FileWorkspaceMixin, BaseAgent):
|
||||
"""Agent class for interacting with AutoGPT."""
|
||||
|
||||
ThoughtProcessID = Literal["plan", "action", "evaluate"]
|
||||
|
||||
5
autogpts/autogpt/autogpt/file_workspace/__init__.py
Normal file
5
autogpts/autogpt/autogpt/file_workspace/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .file_workspace import FileWorkspace
|
||||
|
||||
__all__ = [
|
||||
"FileWorkspace",
|
||||
]
|
||||
145
autogpts/autogpt/autogpt/file_workspace/file_workspace.py
Normal file
145
autogpts/autogpt/autogpt/file_workspace/file_workspace.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
The FileWorkspace class provides an interface for interacting with a file workspace.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FileWorkspace:
|
||||
"""A class that represents a file workspace."""
|
||||
|
||||
NULL_BYTES = ["\0", "\000", "\x00", "\u0000"]
|
||||
|
||||
on_write_file: Callable[[Path], Any] | None = None
|
||||
"""
|
||||
Event hook, executed after writing a file.
|
||||
|
||||
Params:
|
||||
Path: The path of the file that was written, relative to the workspace root.
|
||||
"""
|
||||
|
||||
def __init__(self, root: str | Path, restrict_to_root: bool):
|
||||
self._root = self._sanitize_path(root)
|
||||
self._restrict_to_root = restrict_to_root
|
||||
|
||||
@property
|
||||
def root(self) -> Path:
|
||||
"""The root directory of the file workspace."""
|
||||
return self._root
|
||||
|
||||
@property
|
||||
def restrict_to_root(self):
|
||||
"""Whether to restrict generated paths to the root."""
|
||||
return self._restrict_to_root
|
||||
|
||||
def initialize(self) -> None:
|
||||
self.root.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
def get_path(self, relative_path: str | Path) -> Path:
|
||||
"""Get the full path for an item in the workspace.
|
||||
|
||||
Parameters:
|
||||
relative_path: The relative path to resolve in the workspace.
|
||||
|
||||
Returns:
|
||||
Path: The resolved path relative to the workspace.
|
||||
"""
|
||||
return self._sanitize_path(
|
||||
relative_path,
|
||||
root=self.root,
|
||||
restrict_to_root=self.restrict_to_root,
|
||||
)
|
||||
|
||||
def open_file(self, path: str | Path, mode: str = "r"):
|
||||
"""Open a file in the workspace."""
|
||||
full_path = self.get_path(path)
|
||||
return open(full_path, mode)
|
||||
|
||||
def read_file(self, path: str | Path):
|
||||
"""Read a file in the workspace."""
|
||||
with self.open_file(path, "r") as file:
|
||||
return file.read()
|
||||
|
||||
def write_file(self, path: str | Path, content: str | bytes):
|
||||
"""Write to a file in the workspace."""
|
||||
with self.open_file(path, "w") as file:
|
||||
file.write(content)
|
||||
|
||||
if self.on_write_file:
|
||||
path = Path(path)
|
||||
if path.is_absolute():
|
||||
path = path.relative_to(self.root)
|
||||
self.on_write_file(path)
|
||||
|
||||
def list_files(self, path: str | Path = "."):
|
||||
"""List all files in a directory in the workspace."""
|
||||
full_path = self.get_path(path)
|
||||
return [str(file) for file in full_path.glob("*") if file.is_file()]
|
||||
|
||||
def delete_file(self, path: str | Path):
|
||||
"""Delete a file in the workspace."""
|
||||
full_path = self.get_path(path)
|
||||
full_path.unlink()
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_path(
|
||||
relative_path: str | Path,
|
||||
root: Optional[str | Path] = None,
|
||||
restrict_to_root: bool = True,
|
||||
) -> Path:
|
||||
"""Resolve the relative path within the given root if possible.
|
||||
|
||||
Parameters:
|
||||
relative_path: The relative path to resolve.
|
||||
root: The root path to resolve the relative path within.
|
||||
restrict_to_root: Whether to restrict the path to the root.
|
||||
|
||||
Returns:
|
||||
Path: The resolved path.
|
||||
|
||||
Raises:
|
||||
ValueError: If the path is absolute and a root is provided.
|
||||
ValueError: If the path is outside the root and the root is restricted.
|
||||
"""
|
||||
|
||||
# Posix systems disallow null bytes in paths. Windows is agnostic about it.
|
||||
# Do an explicit check here for all sorts of null byte representations.
|
||||
|
||||
for null_byte in FileWorkspace.NULL_BYTES:
|
||||
if null_byte in str(relative_path) or null_byte in str(root):
|
||||
raise ValueError("embedded null byte")
|
||||
|
||||
if root is None:
|
||||
return Path(relative_path).resolve()
|
||||
|
||||
logger.debug(f"Resolving path '{relative_path}' in workspace '{root}'")
|
||||
|
||||
root, relative_path = Path(root).resolve(), Path(relative_path)
|
||||
|
||||
logger.debug(f"Resolved root as '{root}'")
|
||||
|
||||
# Allow absolute paths if they are contained in the workspace.
|
||||
if (
|
||||
relative_path.is_absolute()
|
||||
and restrict_to_root
|
||||
and not relative_path.is_relative_to(root)
|
||||
):
|
||||
raise ValueError(
|
||||
f"Attempted to access absolute path '{relative_path}' in workspace '{root}'."
|
||||
)
|
||||
|
||||
full_path = root.joinpath(relative_path).resolve()
|
||||
|
||||
logger.debug(f"Joined paths as '{full_path}'")
|
||||
|
||||
if restrict_to_root and not full_path.is_relative_to(root):
|
||||
raise ValueError(
|
||||
f"Attempted to access path '{full_path}' outside of workspace '{root}'."
|
||||
)
|
||||
|
||||
return full_path
|
||||
@@ -1,5 +0,0 @@
|
||||
from autogpt.workspace.workspace import Workspace
|
||||
|
||||
__all__ = [
|
||||
"Workspace",
|
||||
]
|
||||
@@ -1,127 +0,0 @@
|
||||
"""
|
||||
=========
|
||||
Workspace
|
||||
=========
|
||||
|
||||
The workspace is a directory containing configuration and working files for an AutoGPT
|
||||
agent.
|
||||
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Workspace:
|
||||
"""A class that represents a workspace for an AutoGPT agent."""
|
||||
|
||||
NULL_BYTES = ["\0", "\000", "\x00", "\u0000"]
|
||||
|
||||
def __init__(self, workspace_root: str | Path, restrict_to_workspace: bool):
|
||||
self._root = self._sanitize_path(workspace_root)
|
||||
self._restrict_to_workspace = restrict_to_workspace
|
||||
|
||||
@property
|
||||
def root(self) -> Path:
|
||||
"""The root directory of the workspace."""
|
||||
return self._root
|
||||
|
||||
@property
|
||||
def restrict_to_workspace(self):
|
||||
"""Whether to restrict generated paths to the workspace."""
|
||||
return self._restrict_to_workspace
|
||||
|
||||
def initialize(self) -> None:
|
||||
self.root.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
def get_path(self, relative_path: str | Path) -> Path:
|
||||
"""Get the full path for an item in the workspace.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
relative_path
|
||||
The relative path to resolve in the workspace.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Path
|
||||
The resolved path relative to the workspace.
|
||||
|
||||
"""
|
||||
return self._sanitize_path(
|
||||
relative_path,
|
||||
root=self.root,
|
||||
restrict_to_root=self.restrict_to_workspace,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_path(
|
||||
relative_path: str | Path,
|
||||
root: Optional[str | Path] = None,
|
||||
restrict_to_root: bool = True,
|
||||
) -> Path:
|
||||
"""Resolve the relative path within the given root if possible.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
relative_path
|
||||
The relative path to resolve.
|
||||
root
|
||||
The root path to resolve the relative path within.
|
||||
restrict_to_root
|
||||
Whether to restrict the path to the root.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Path
|
||||
The resolved path.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the path is absolute and a root is provided.
|
||||
ValueError
|
||||
If the path is outside the root and the root is restricted.
|
||||
|
||||
"""
|
||||
|
||||
# Posix systems disallow null bytes in paths. Windows is agnostic about it.
|
||||
# Do an explicit check here for all sorts of null byte representations.
|
||||
|
||||
for null_byte in Workspace.NULL_BYTES:
|
||||
if null_byte in str(relative_path) or null_byte in str(root):
|
||||
raise ValueError("embedded null byte")
|
||||
|
||||
if root is None:
|
||||
return Path(relative_path).resolve()
|
||||
|
||||
logger.debug(f"Resolving path '{relative_path}' in workspace '{root}'")
|
||||
|
||||
root, relative_path = Path(root).resolve(), Path(relative_path)
|
||||
|
||||
logger.debug(f"Resolved root as '{root}'")
|
||||
|
||||
# Allow exception for absolute paths if they are contained in your workspace directory.
|
||||
if (
|
||||
relative_path.is_absolute()
|
||||
and restrict_to_root
|
||||
and not relative_path.is_relative_to(root)
|
||||
):
|
||||
raise ValueError(
|
||||
f"Attempted to access absolute path '{relative_path}' in workspace '{root}'."
|
||||
)
|
||||
|
||||
full_path = root.joinpath(relative_path).resolve()
|
||||
|
||||
logger.debug(f"Joined paths as '{full_path}'")
|
||||
|
||||
if restrict_to_root and not full_path.is_relative_to(root):
|
||||
raise ValueError(
|
||||
f"Attempted to access path '{full_path}' outside of workspace '{root}'."
|
||||
)
|
||||
|
||||
return full_path
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import run_challenge
|
||||
|
||||
@@ -16,7 +16,7 @@ def test_browse_website(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
run_challenge(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from autogpt.config import Config
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import get_workspace_path, run_challenge
|
||||
|
||||
@@ -23,7 +23,7 @@ def test_write_file(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
run_challenge(
|
||||
|
||||
@@ -6,7 +6,7 @@ from _pytest.config.argparsing import Parser
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge import Challenge
|
||||
from tests.vcr import before_record_response
|
||||
|
||||
@@ -64,12 +64,14 @@ def check_beat_challenges(request: FixtureRequest) -> None:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patched_make_workspace(mocker: MockerFixture, workspace: Workspace) -> Generator:
|
||||
def patched_make_workspace(
|
||||
mocker: MockerFixture, workspace: FileWorkspace
|
||||
) -> Generator:
|
||||
def patched_make_workspace(*args: Any, **kwargs: Any) -> str:
|
||||
return workspace.root
|
||||
|
||||
mocker.patch.object(
|
||||
Workspace,
|
||||
FileWorkspace,
|
||||
"make_workspace",
|
||||
new=patched_make_workspace,
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.agents import Agent
|
||||
from autogpt.commands.execute_code import execute_python_file
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import (
|
||||
copy_file_into_workspace,
|
||||
@@ -32,7 +32,7 @@ def test_debug_code_challenge_a(
|
||||
patched_api_requestor: MockerFixture,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.basic_abilities.test_browse_website import USER_INPUTS
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import get_workspace_path, run_challenge
|
||||
@@ -23,7 +23,7 @@ def test_information_retrieval_challenge_a(
|
||||
patched_api_requestor: MockerFixture,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import get_workspace_path, run_challenge
|
||||
|
||||
@@ -18,7 +18,7 @@ def test_information_retrieval_challenge_b(
|
||||
patched_api_requestor: MockerFixture,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import get_workspace_path, run_challenge
|
||||
|
||||
@@ -22,7 +22,7 @@ def test_information_retrieval_challenge_c(
|
||||
patched_api_requestor: MockerFixture,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
|
||||
@@ -4,7 +4,7 @@ import pytest
|
||||
import yaml
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import get_workspace_path, run_challenge
|
||||
|
||||
@@ -19,7 +19,7 @@ def test_kubernetes_template_challenge_a(
|
||||
patched_api_requestor: MockerFixture,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@ import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.config import Config
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import get_workspace_path, run_challenge
|
||||
|
||||
@@ -18,7 +18,7 @@ def test_memory_challenge_a(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -44,7 +44,7 @@ def test_memory_challenge_a(
|
||||
|
||||
|
||||
def create_instructions_files(
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
num_files: int,
|
||||
task_id: str,
|
||||
base_filename: str = "instructions_",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import generate_noise, get_workspace_path, run_challenge
|
||||
|
||||
@@ -16,7 +16,7 @@ def test_memory_challenge_b(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -44,7 +44,7 @@ def test_memory_challenge_b(
|
||||
|
||||
|
||||
def create_instructions_files(
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
level: int,
|
||||
task_ids: list,
|
||||
base_filename: str = "instructions_",
|
||||
|
||||
@@ -2,7 +2,7 @@ import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.commands.file_operations import read_file
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import generate_noise, get_workspace_path, run_challenge
|
||||
|
||||
@@ -17,7 +17,7 @@ def test_memory_challenge_c(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -62,7 +62,7 @@ def test_memory_challenge_c(
|
||||
|
||||
|
||||
def create_instructions_files(
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
level: int,
|
||||
task_ids: list,
|
||||
base_filename: str = "instructions_",
|
||||
|
||||
@@ -5,7 +5,7 @@ import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from autogpt.commands.file_operations import read_file
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from tests.challenges.challenge_decorator.challenge_decorator import challenge
|
||||
from tests.challenges.utils import get_workspace_path, run_challenge
|
||||
|
||||
@@ -21,7 +21,7 @@ def test_memory_challenge_d(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
level_to_run: int,
|
||||
challenge_name: str,
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
patched_make_workspace: pytest.fixture,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -173,7 +173,7 @@ def extract_beliefs(content: str) -> Dict[str, Dict[str, str]]:
|
||||
|
||||
|
||||
def create_instructions_files(
|
||||
workspace: Workspace,
|
||||
workspace: FileWorkspace,
|
||||
level: int,
|
||||
test_phrases: list,
|
||||
base_filename: str = "instructions_",
|
||||
|
||||
@@ -7,8 +7,8 @@ from typing import Any, AsyncIterator
|
||||
import pytest
|
||||
|
||||
from agbenchmark_config.benchmarks import run_specific_agent
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from autogpt.logs import LogCycleHandler
|
||||
from autogpt.workspace import Workspace
|
||||
from tests.challenges.schema import Task
|
||||
|
||||
|
||||
@@ -55,12 +55,12 @@ def setup_mock_log_cycle_agent_name(
|
||||
)
|
||||
|
||||
|
||||
def get_workspace_path(workspace: Workspace, file_name: str) -> str:
|
||||
def get_workspace_path(workspace: FileWorkspace, file_name: str) -> str:
|
||||
return str(workspace.get_path(file_name))
|
||||
|
||||
|
||||
def copy_file_into_workspace(
|
||||
workspace: Workspace, directory_path: Path, file_path: str
|
||||
workspace: FileWorkspace, directory_path: Path, file_path: str
|
||||
) -> None:
|
||||
workspace_code_file_path = get_workspace_path(workspace, file_path)
|
||||
code_file_path = directory_path / file_path
|
||||
|
||||
@@ -10,11 +10,11 @@ from autogpt.agents.agent import Agent, AgentConfiguration, AgentSettings
|
||||
from autogpt.app.main import _configure_openai_provider
|
||||
from autogpt.config import AIProfile, Config, ConfigBuilder
|
||||
from autogpt.core.resource.model_providers import ChatModelProvider, OpenAIProvider
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from autogpt.llm.api_manager import ApiManager
|
||||
from autogpt.logs.config import configure_logging
|
||||
from autogpt.memory.vector import get_memory
|
||||
from autogpt.models.command_registry import CommandRegistry
|
||||
from autogpt.workspace import Workspace
|
||||
|
||||
pytest_plugins = [
|
||||
"tests.integration.agent_factory",
|
||||
@@ -44,8 +44,8 @@ def workspace_root(agent_data_dir: Path) -> Path:
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def workspace(workspace_root: Path) -> Workspace:
|
||||
workspace = Workspace(workspace_root, restrict_to_workspace=True)
|
||||
def workspace(workspace_root: Path) -> FileWorkspace:
|
||||
workspace = FileWorkspace(workspace_root, restrict_to_root=True)
|
||||
workspace.initialize()
|
||||
return workspace
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@ import orjson
|
||||
import pytest
|
||||
|
||||
from autogpt.config import Config
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from autogpt.memory.vector import JSONFileMemory, MemoryItem
|
||||
from autogpt.workspace import Workspace
|
||||
|
||||
|
||||
def test_json_memory_init_without_backing_file(config: Config, workspace: Workspace):
|
||||
def test_json_memory_init_without_backing_file(
|
||||
config: Config, workspace: FileWorkspace
|
||||
):
|
||||
index_file = workspace.root / f"{config.memory_index}.json"
|
||||
|
||||
assert not index_file.exists()
|
||||
@@ -17,7 +19,9 @@ def test_json_memory_init_without_backing_file(config: Config, workspace: Worksp
|
||||
assert index_file.read_text() == "[]"
|
||||
|
||||
|
||||
def test_json_memory_init_with_backing_empty_file(config: Config, workspace: Workspace):
|
||||
def test_json_memory_init_with_backing_empty_file(
|
||||
config: Config, workspace: FileWorkspace
|
||||
):
|
||||
index_file = workspace.root / f"{config.memory_index}.json"
|
||||
index_file.touch()
|
||||
|
||||
@@ -28,7 +32,7 @@ def test_json_memory_init_with_backing_empty_file(config: Config, workspace: Wor
|
||||
|
||||
|
||||
def test_json_memory_init_with_backing_invalid_file(
|
||||
config: Config, workspace: Workspace
|
||||
config: Config, workspace: FileWorkspace
|
||||
):
|
||||
index_file = workspace.root / f"{config.memory_index}.json"
|
||||
index_file.touch()
|
||||
|
||||
@@ -6,16 +6,29 @@ 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
|
||||
from autogpt.config.ai_profile import AIProfile
|
||||
|
||||
|
||||
@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"])
|
||||
directives = AIDirectives(
|
||||
resources=["Resource1"],
|
||||
constraints=["Constraint1"],
|
||||
best_practices=["BestPractice1"],
|
||||
)
|
||||
|
||||
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"])
|
||||
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"
|
||||
@@ -27,7 +40,11 @@ async def test_apply_overrides_to_ai_settings():
|
||||
@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"])
|
||||
directives = AIDirectives(
|
||||
resources=["Resource1"],
|
||||
constraints=["Constraint1"],
|
||||
best_practices=["BestPractice1"],
|
||||
)
|
||||
|
||||
user_inputs = [
|
||||
"y",
|
||||
@@ -41,7 +58,9 @@ async def test_interactively_revise_ai_settings(config: Config):
|
||||
"",
|
||||
]
|
||||
with patch("autogpt.app.utils.clean_input", side_effect=user_inputs):
|
||||
ai_profile, directives = await interactively_revise_ai_settings(ai_profile, directives, config)
|
||||
ai_profile, directives = await interactively_revise_ai_settings(
|
||||
ai_profile, directives, config
|
||||
)
|
||||
|
||||
assert ai_profile.ai_name == "New AI"
|
||||
assert ai_profile.ai_role == "New Role"
|
||||
|
||||
@@ -11,7 +11,7 @@ import pytest
|
||||
|
||||
from autogpt.app.configurator import GPT_3_MODEL, GPT_4_MODEL, apply_overrides_to_config
|
||||
from autogpt.config import Config, ConfigBuilder
|
||||
from autogpt.workspace.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
|
||||
|
||||
def test_initial_values(config: Config) -> None:
|
||||
@@ -122,7 +122,7 @@ def test_smart_and_fast_llms_set_to_gpt4(mock_list_models: Any, config: Config)
|
||||
config.smart_llm = smart_llm
|
||||
|
||||
|
||||
def test_missing_azure_config(workspace: Workspace) -> None:
|
||||
def test_missing_azure_config(workspace: FileWorkspace) -> None:
|
||||
config_file = workspace.get_path("azure_config.yaml")
|
||||
with pytest.raises(FileNotFoundError):
|
||||
ConfigBuilder.load_azure_config(config_file)
|
||||
@@ -136,7 +136,7 @@ def test_missing_azure_config(workspace: Workspace) -> None:
|
||||
assert azure_config["azure_model_to_deployment_id_map"] == {}
|
||||
|
||||
|
||||
def test_azure_config(config: Config, workspace: Workspace) -> None:
|
||||
def test_azure_config(config: Config, workspace: FileWorkspace) -> None:
|
||||
config_file = workspace.get_path("azure_config.yaml")
|
||||
yaml_content = """
|
||||
azure_api_type: azure
|
||||
|
||||
@@ -15,9 +15,9 @@ import autogpt.commands.file_operations as file_ops
|
||||
from autogpt.agents.agent import Agent
|
||||
from autogpt.agents.utils.exceptions import DuplicateOperationError
|
||||
from autogpt.config import Config
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
from autogpt.memory.vector.memory_item import MemoryItem
|
||||
from autogpt.memory.vector.utils import Embedding
|
||||
from autogpt.workspace import Workspace
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@@ -50,7 +50,7 @@ def test_file_name():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_file_path(test_file_name: Path, workspace: Workspace):
|
||||
def test_file_path(test_file_name: Path, workspace: FileWorkspace):
|
||||
return workspace.get_path(test_file_name)
|
||||
|
||||
|
||||
@@ -73,12 +73,12 @@ def test_file_with_content_path(test_file: TextIOWrapper, file_content, agent: A
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def test_directory(workspace: Workspace):
|
||||
def test_directory(workspace: FileWorkspace):
|
||||
return workspace.get_path("test_directory")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def test_nested_file(workspace: Workspace):
|
||||
def test_nested_file(workspace: FileWorkspace):
|
||||
return workspace.get_path("nested/test_file.txt")
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@ def test_append_to_file_uses_checksum_from_appended_file(
|
||||
)
|
||||
|
||||
|
||||
def test_list_files(workspace: Workspace, test_directory: Path, agent: Agent):
|
||||
def test_list_files(workspace: FileWorkspace, test_directory: Path, agent: Agent):
|
||||
# Case 1: Create files A and B, search for A, and ensure we don't return A and B
|
||||
file_a = workspace.get_path("file_a.txt")
|
||||
file_b = workspace.get_path("file_b.txt")
|
||||
|
||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from autogpt.workspace import Workspace
|
||||
from autogpt.file_workspace import FileWorkspace
|
||||
|
||||
_WORKSPACE_ROOT = Path("home/users/monty/auto_gpt_workspace")
|
||||
|
||||
@@ -40,7 +40,7 @@ _INACCESSIBLE_PATHS = (
|
||||
"test_folder/{null_byte}",
|
||||
"test_folder/{null_byte}test_file.txt",
|
||||
],
|
||||
Workspace.NULL_BYTES,
|
||||
FileWorkspace.NULL_BYTES,
|
||||
)
|
||||
]
|
||||
+ [
|
||||
@@ -68,7 +68,7 @@ def inaccessible_path(request):
|
||||
|
||||
|
||||
def test_sanitize_path_accessible(accessible_path, workspace_root):
|
||||
full_path = Workspace._sanitize_path(
|
||||
full_path = FileWorkspace._sanitize_path(
|
||||
accessible_path,
|
||||
root=workspace_root,
|
||||
restrict_to_root=True,
|
||||
@@ -79,7 +79,7 @@ def test_sanitize_path_accessible(accessible_path, workspace_root):
|
||||
|
||||
def test_sanitize_path_inaccessible(inaccessible_path, workspace_root):
|
||||
with pytest.raises(ValueError):
|
||||
Workspace._sanitize_path(
|
||||
FileWorkspace._sanitize_path(
|
||||
inaccessible_path,
|
||||
root=workspace_root,
|
||||
restrict_to_root=True,
|
||||
@@ -87,13 +87,13 @@ def test_sanitize_path_inaccessible(inaccessible_path, workspace_root):
|
||||
|
||||
|
||||
def test_get_path_accessible(accessible_path, workspace_root):
|
||||
workspace = Workspace(workspace_root, True)
|
||||
workspace = FileWorkspace(workspace_root, True)
|
||||
full_path = workspace.get_path(accessible_path)
|
||||
assert full_path.is_absolute()
|
||||
assert full_path.is_relative_to(workspace_root)
|
||||
|
||||
|
||||
def test_get_path_inaccessible(inaccessible_path, workspace_root):
|
||||
workspace = Workspace(workspace_root, True)
|
||||
workspace = FileWorkspace(workspace_root, True)
|
||||
with pytest.raises(ValueError):
|
||||
workspace.get_path(inaccessible_path)
|
||||
|
||||
Reference in New Issue
Block a user