mirror of https://github.com/kortix-ai/suna.git
clean and shell
This commit is contained in:
parent
87129a1e61
commit
01c1501198
|
@ -4,10 +4,12 @@ from agentpress.tool import ToolResult, openapi_schema, xml_schema
|
||||||
from agent.tools.utils.daytona_sandbox import SandboxToolsBase
|
from agent.tools.utils.daytona_sandbox import SandboxToolsBase
|
||||||
import os
|
import os
|
||||||
|
|
||||||
WORKSPACE_PATH = "/workspace"
|
# TODO: might want to be more granular with the tool names:
|
||||||
|
# file_read - Read file content. Use for checking file contents, analyzing logs, or reading configuration files.
|
||||||
def clean_path(path: str) -> str:
|
# file_write - Overwrite or append content to a file. Use for creating new files, appending content, or modifying existing files.
|
||||||
return path.replace(WORKSPACE_PATH, "").lstrip("/")
|
# file_str_replace - Replace specified string in a file. Use for updating specific content in files or fixing errors in code.
|
||||||
|
# file_find_in_content - Search for matching text within file content. Use for finding specific content or patterns in files.
|
||||||
|
# file_find_by_name - Find files by name pattern in specified directory. Use for locating files with specific naming patterns.
|
||||||
|
|
||||||
|
|
||||||
class SandboxFilesTool(SandboxToolsBase):
|
class SandboxFilesTool(SandboxToolsBase):
|
||||||
|
@ -83,7 +85,7 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
"""Get the current workspace state by reading all files"""
|
"""Get the current workspace state by reading all files"""
|
||||||
files_state = {}
|
files_state = {}
|
||||||
try:
|
try:
|
||||||
files = self.sandbox.fs.list_files(WORKSPACE_PATH)
|
files = self.sandbox.fs.list_files(self.workspace_path)
|
||||||
for file_info in files:
|
for file_info in files:
|
||||||
rel_path = file_info.name
|
rel_path = file_info.name
|
||||||
|
|
||||||
|
@ -92,7 +94,7 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
full_path = f"{WORKSPACE_PATH}/{rel_path}"
|
full_path = f"{self.workspace_path}/{rel_path}"
|
||||||
content = self.sandbox.fs.download_file(full_path).decode()
|
content = self.sandbox.fs.download_file(full_path).decode()
|
||||||
files_state[rel_path] = {
|
files_state[rel_path] = {
|
||||||
"content": content,
|
"content": content,
|
||||||
|
@ -149,9 +151,9 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
async def create_file(self, file_path: str, file_contents: str, permissions: str = "644") -> ToolResult:
|
async def create_file(self, file_path: str, file_contents: str, permissions: str = "644") -> ToolResult:
|
||||||
file_path = clean_path(file_path)
|
file_path = self.clean_path(file_path)
|
||||||
try:
|
try:
|
||||||
full_path = f"{WORKSPACE_PATH}/{file_path}"
|
full_path = f"{self.workspace_path}/{file_path}"
|
||||||
if self._file_exists(full_path):
|
if self._file_exists(full_path):
|
||||||
return self.fail_response(f"File '{file_path}' already exists. Use update_file to modify existing files.")
|
return self.fail_response(f"File '{file_path}' already exists. Use update_file to modify existing files.")
|
||||||
|
|
||||||
|
@ -209,8 +211,8 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
)
|
)
|
||||||
async def str_replace(self, file_path: str, old_str: str, new_str: str) -> ToolResult:
|
async def str_replace(self, file_path: str, old_str: str, new_str: str) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
file_path = clean_path(file_path)
|
file_path = self.clean_path(file_path)
|
||||||
full_path = f"{WORKSPACE_PATH}/{file_path}"
|
full_path = f"{self.workspace_path}/{file_path}"
|
||||||
if not self._file_exists(full_path):
|
if not self._file_exists(full_path):
|
||||||
return self.fail_response(f"File '{file_path}' does not exist")
|
return self.fail_response(f"File '{file_path}' does not exist")
|
||||||
|
|
||||||
|
@ -281,8 +283,8 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
)
|
)
|
||||||
async def full_file_rewrite(self, file_path: str, file_contents: str, permissions: str = "644") -> ToolResult:
|
async def full_file_rewrite(self, file_path: str, file_contents: str, permissions: str = "644") -> ToolResult:
|
||||||
try:
|
try:
|
||||||
file_path = clean_path(file_path)
|
file_path = self.clean_path(file_path)
|
||||||
full_path = f"{WORKSPACE_PATH}/{file_path}"
|
full_path = f"{self.workspace_path}/{file_path}"
|
||||||
if not self._file_exists(full_path):
|
if not self._file_exists(full_path):
|
||||||
return self.fail_response(f"File '{file_path}' does not exist. Use create_file to create a new file.")
|
return self.fail_response(f"File '{file_path}' does not exist. Use create_file to create a new file.")
|
||||||
|
|
||||||
|
@ -322,8 +324,8 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
)
|
)
|
||||||
async def delete_file(self, file_path: str) -> ToolResult:
|
async def delete_file(self, file_path: str) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
file_path = clean_path(file_path)
|
file_path = self.clean_path(file_path)
|
||||||
full_path = f"{WORKSPACE_PATH}/{file_path}"
|
full_path = f"{self.workspace_path}/{file_path}"
|
||||||
if not self._file_exists(full_path):
|
if not self._file_exists(full_path):
|
||||||
return self.fail_response(f"File '{file_path}' does not exist")
|
return self.fail_response(f"File '{file_path}' does not exist")
|
||||||
|
|
||||||
|
@ -366,8 +368,8 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
)
|
)
|
||||||
async def search_files(self, path: str, pattern: str) -> ToolResult:
|
async def search_files(self, path: str, pattern: str) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
path = clean_path(path)
|
path = self.clean_path(path)
|
||||||
full_path = f"{WORKSPACE_PATH}/{path}" if not path.startswith(WORKSPACE_PATH) else path
|
full_path = f"{self.workspace_path}/{path}" if not path.startswith(self.workspace_path) else path
|
||||||
results = self.sandbox.fs.find_files(
|
results = self.sandbox.fs.find_files(
|
||||||
path=full_path,
|
path=full_path,
|
||||||
pattern=pattern
|
pattern=pattern
|
||||||
|
@ -436,8 +438,8 @@ class SandboxFilesTool(SandboxToolsBase):
|
||||||
)
|
)
|
||||||
async def replace_in_files(self, files: list[str], pattern: str, new_value: str) -> ToolResult:
|
async def replace_in_files(self, files: list[str], pattern: str, new_value: str) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
files = [clean_path(f) for f in files]
|
files = [self.clean_path(f) for f in files]
|
||||||
full_paths = [f"{WORKSPACE_PATH}/{f}" if not f.startswith(WORKSPACE_PATH) else f for f in files]
|
full_paths = [f"{self.workspace_path}/{f}" if not f.startswith(self.workspace_path) else f for f in files]
|
||||||
self.sandbox.fs.replace_in_files(
|
self.sandbox.fs.replace_in_files(
|
||||||
files=full_paths,
|
files=full_paths,
|
||||||
pattern=pattern,
|
pattern=pattern,
|
||||||
|
|
|
@ -2,11 +2,6 @@ from agentpress.tool import ToolResult, openapi_schema, xml_schema
|
||||||
from agent.tools.utils.daytona_sandbox import SandboxToolsBase
|
from agent.tools.utils.daytona_sandbox import SandboxToolsBase
|
||||||
|
|
||||||
# TODO: might want to be more granular with the tool names:
|
# TODO: might want to be more granular with the tool names:
|
||||||
# file_read - Read file content. Use for checking file contents, analyzing logs, or reading configuration files.
|
|
||||||
# file_write - Overwrite or append content to a file. Use for creating new files, appending content, or modifying existing files.
|
|
||||||
# file_str_replace - Replace specified string in a file. Use for updating specific content in files or fixing errors in code.
|
|
||||||
# file_find_in_content - Search for matching text within file content. Use for finding specific content or patterns in files.
|
|
||||||
# file_find_by_name - Find files by name pattern in specified directory. Use for locating files with specific naming patterns.
|
|
||||||
# shell_exec - Execute commands in a specified shell session. Use for running code, installing packages, or managing files.
|
# shell_exec - Execute commands in a specified shell session. Use for running code, installing packages, or managing files.
|
||||||
# shell_view - View the content of a specified shell session. Use for checking command execution results or monitoring output.
|
# shell_view - View the content of a specified shell session. Use for checking command execution results or monitoring output.
|
||||||
# shell_wait - Wait for the running process in a specified shell session to return. Use after running commands that require longer runtime.
|
# shell_wait - Wait for the running process in a specified shell session to return. Use after running commands that require longer runtime.
|
||||||
|
@ -14,6 +9,7 @@ from agent.tools.utils.daytona_sandbox import SandboxToolsBase
|
||||||
# shell_kill_process - Terminate a running process in a specified shell session. Use for stopping long-running processes or handling frozen commands.
|
# shell_kill_process - Terminate a running process in a specified shell session. Use for stopping long-running processes or handling frozen commands.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SandboxShellTool(SandboxToolsBase):
|
class SandboxShellTool(SandboxToolsBase):
|
||||||
"""Tool for executing tasks in a Daytona sandbox with browser-use capabilities."""
|
"""Tool for executing tasks in a Daytona sandbox with browser-use capabilities."""
|
||||||
|
|
||||||
|
@ -25,7 +21,7 @@ class SandboxShellTool(SandboxToolsBase):
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "execute_command",
|
"name": "execute_command",
|
||||||
"description": "Execute a shell command in the workspace directory",
|
"description": "Execute a shell command in the workspace directory. Working directory is the workspace directory.",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -51,7 +47,7 @@ class SandboxShellTool(SandboxToolsBase):
|
||||||
)
|
)
|
||||||
async def execute_command(self, command: str, folder: str = None) -> ToolResult:
|
async def execute_command(self, command: str, folder: str = None) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
folder = folder or self.sandbox.get_user_root_dir()
|
folder = folder or self.workspace_path
|
||||||
response = self.sandbox.process.exec(command, cwd=folder, timeout=60)
|
response = self.sandbox.process.exec(command, cwd=folder, timeout=60)
|
||||||
|
|
||||||
if response.exit_code == 0:
|
if response.exit_code == 0:
|
||||||
|
@ -66,3 +62,14 @@ class SandboxShellTool(SandboxToolsBase):
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return self.fail_response(f"Error executing command: {str(e)}")
|
return self.fail_response(f"Error executing command: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def test_shell_tool():
|
||||||
|
shell_tool = SandboxShellTool(
|
||||||
|
sandbox_id="sandbox-15a2c059",
|
||||||
|
password="vvv"
|
||||||
|
)
|
||||||
|
print("1)", "*"*10)
|
||||||
|
res = await shell_tool.execute_command("ls -l")
|
||||||
|
print(res)
|
||||||
|
|
|
@ -279,6 +279,7 @@ class SandboxToolsBase(Tool):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.sandbox = None
|
self.sandbox = None
|
||||||
self.daytona = daytona
|
self.daytona = daytona
|
||||||
|
self.workspace_path = "/workspace"
|
||||||
|
|
||||||
self.sandbox_id = sandbox_id
|
self.sandbox_id = sandbox_id
|
||||||
try:
|
try:
|
||||||
|
@ -293,3 +294,6 @@ class SandboxToolsBase(Tool):
|
||||||
print(self.sandbox.get_preview_link(6080))
|
print(self.sandbox.get_preview_link(6080))
|
||||||
print(self.sandbox.get_preview_link(8080))
|
print(self.sandbox.get_preview_link(8080))
|
||||||
print("***\033[0m")
|
print("***\033[0m")
|
||||||
|
|
||||||
|
def clean_path(self, path: str) -> str:
|
||||||
|
return path.replace(self.workspace_path, "").lstrip("/")
|
||||||
|
|
Loading…
Reference in New Issue