Complete context integration & add close_context_item command

This commit is contained in:
Reinier van der Leer
2023-08-23 01:01:52 +02:00
parent b0405ac8ee
commit 092afbce62
5 changed files with 63 additions and 23 deletions

View File

@@ -177,14 +177,11 @@ class Agent(ContextMixin, WorkspaceMixin, BaseAgent):
return_value[1], ContextItem
):
context_item = return_value[1]
# return_value = return_value[0]
return_value = return_value[0]
logger.debug(
f"Command {command_name} returned a ContextItem: {context_item}"
)
# self.context.add(context_item)
# HACK: use content of ContextItem as return value, for legacy support
return_value = context_item.content
self.context.add(context_item)
result = ActionSuccessResult(return_value)
except AgentException as e:

View File

@@ -102,7 +102,7 @@ class BaseAgent(metaclass=ABCMeta):
super(BaseAgent, self).__init__()
@property
def system_prompt(self):
def system_prompt(self) -> str:
"""
The system prompt sets up the AI's personality and explains its goals,
available resources, and restrictions.
@@ -297,7 +297,7 @@ class BaseAgent(metaclass=ABCMeta):
return (
f"Respond strictly with JSON{', and also specify a command to use through a function_call' if use_functions else ''}. "
"The JSON should be compatible with the TypeScript type `Response` from the following:\n"
f"{response_format}\n"
f"{response_format}"
)
def on_before_think(

View File

@@ -23,7 +23,7 @@ from autogpt.models.context_item import FileContextItem, FolderContextItem
from .decorators import sanitize_path_arg
def compatible_with_agent(agent: BaseAgent) -> bool:
def agent_implements_context(agent: BaseAgent) -> bool:
return isinstance(agent, ContextMixin)
@@ -37,7 +37,7 @@ def compatible_with_agent(agent: BaseAgent) -> bool:
"required": True,
}
},
available=compatible_with_agent,
available=agent_implements_context,
)
@sanitize_path_arg("file_path")
def open_file(file_path: Path, agent: Agent) -> tuple[str, FileContextItem]:
@@ -51,8 +51,9 @@ def open_file(file_path: Path, agent: Agent) -> tuple[str, FileContextItem]:
FileContextItem: A ContextItem representing the opened file
"""
# Try to make the file path relative
relative_file_path = None
with contextlib.suppress(ValueError):
file_path = file_path.relative_to(agent.workspace.root)
relative_file_path = file_path.relative_to(agent.workspace.root)
assert (agent_context := get_agent_context(agent)) is not None
@@ -63,12 +64,14 @@ def open_file(file_path: Path, agent: Agent) -> tuple[str, FileContextItem]:
elif not file_path.is_file():
raise CommandExecutionError(f"{file_path} exists but is not a file")
file = FileContextItem(file_path)
file_path = relative_file_path or file_path
file = FileContextItem(file_path, agent.workspace.root)
if file in agent_context:
raise DuplicateOperationError(f"The file {file_path} is already open")
return (
f"File {file}{' created,' if created else ''} opened and added to context ✅",
f"File {file_path}{' created,' if created else ''} opened and added to context ✅",
file,
)
@@ -83,7 +86,7 @@ def open_file(file_path: Path, agent: Agent) -> tuple[str, FileContextItem]:
"required": True,
}
},
available=compatible_with_agent,
available=agent_implements_context,
)
@sanitize_path_arg("path")
def open_folder(path: Path, agent: Agent) -> tuple[str, FolderContextItem]:
@@ -97,8 +100,9 @@ def open_folder(path: Path, agent: Agent) -> tuple[str, FolderContextItem]:
FolderContextItem: A ContextItem representing the opened folder
"""
# Try to make the path relative
relative_path = None
with contextlib.suppress(ValueError):
path = path.relative_to(agent.workspace.root)
relative_path = path.relative_to(agent.workspace.root)
assert (agent_context := get_agent_context(agent)) is not None
@@ -107,8 +111,10 @@ def open_folder(path: Path, agent: Agent) -> tuple[str, FolderContextItem]:
elif not path.is_dir():
raise CommandExecutionError(f"{path} exists but is not a folder")
folder = FolderContextItem(path)
path = relative_path or path
folder = FolderContextItem(path, agent.workspace.root)
if folder in agent_context:
raise DuplicateOperationError(f"The folder {path} is already open")
return f"Folder {folder} opened and added to context ✅", folder
return f"Folder {path} opened and added to context ✅", folder

View File

@@ -6,8 +6,13 @@ COMMAND_CATEGORY = "system"
COMMAND_CATEGORY_TITLE = "System"
import logging
from typing import TYPE_CHECKING
from autogpt.agents.agent import Agent
if TYPE_CHECKING:
from autogpt.agents.agent import Agent
from autogpt.agents.features.context import get_agent_context
from autogpt.agents.utils.exceptions import InvalidArgumentError
from autogpt.command_decorator import command
logger = logging.getLogger(__name__)
@@ -36,3 +41,25 @@ def task_complete(reason: str, agent: Agent) -> None:
"""
logger.info(reason, extra={"title": "Shutting down...\n"})
quit()
@command(
"close_context_item",
"Close an open file, folder or other context item",
{
"index": {
"type": "integer",
"description": "The 1-based index of the context item to close",
"required": True,
}
},
available=lambda a: get_agent_context(a) is not None,
)
def close_context_item(index: int, agent: Agent) -> str:
assert (context := get_agent_context(agent)) is not None
if index > len(context.items) or index == 0:
raise InvalidArgumentError(f"Index {index} out of range")
context.close(index)
return f"Context item {index} closed ✅"

View File

@@ -39,15 +39,20 @@ class ContextItem(ABC):
@dataclass
class FileContextItem(ContextItem):
file_path: Path
file_path_in_workspace: Path
workspace_path: Path
@property
def file_path(self) -> Path:
return self.workspace_path / self.file_path_in_workspace
@property
def description(self) -> str:
return f"The current content of the file '{self.file_path}'"
return f"The current content of the file '{self.file_path_in_workspace}'"
@property
def source(self) -> str:
return str(self.file_path)
return str(self.file_path_in_workspace)
@property
def content(self) -> str:
@@ -56,7 +61,12 @@ class FileContextItem(ContextItem):
@dataclass
class FolderContextItem(ContextItem):
path: Path
path_in_workspace: Path
workspace_path: Path
@property
def path(self) -> Path:
return self.workspace_path / self.path_in_workspace
def __post_init__(self) -> None:
assert self.path.exists(), "Selected path does not exist"
@@ -64,11 +74,11 @@ class FolderContextItem(ContextItem):
@property
def description(self) -> str:
return f"The contents of the folder '{self.path}' in the workspace"
return f"The contents of the folder '{self.path_in_workspace}' in the workspace"
@property
def source(self) -> str:
return str(self.path)
return str(self.path_in_workspace)
@property
def content(self) -> str: