diff --git a/app/agent/browser.py b/app/agent/browser.py index 9d20827..3f25c45 100644 --- a/app/agent/browser.py +++ b/app/agent/browser.py @@ -8,7 +8,7 @@ from app.logger import logger from app.prompt.browser import NEXT_STEP_PROMPT, SYSTEM_PROMPT from app.schema import Message, ToolChoice from app.tool import BrowserUseTool, Terminate, ToolCollection -from app.tool.sb_browser_tool import SandboxBrowserTool +from app.tool.sandbox.sb_browser_tool import SandboxBrowserTool # Avoid circular import if BrowserAgent needs BrowserContextHelper diff --git a/app/agent/sandbox_agent.py b/app/agent/sandbox_agent.py index a510f68..1390e4a 100644 --- a/app/agent/sandbox_agent.py +++ b/app/agent/sandbox_agent.py @@ -13,10 +13,10 @@ from app.tool import Terminate, ToolCollection from app.tool.ask_human import AskHuman from app.tool.browser_use_tool import BrowserUseTool from app.tool.mcp import MCPClients, MCPClientTool -from app.tool.sb_browser_tool import SandboxBrowserTool -from app.tool.sb_files_tool import SandboxFilesTool -from app.tool.sb_shell_tool import SandboxShellTool -from app.tool.sb_vision_tool import SandboxVisionTool +from app.tool.sandbox.sb_browser_tool import SandboxBrowserTool +from app.tool.sandbox.sb_files_tool import SandboxFilesTool +from app.tool.sandbox.sb_shell_tool import SandboxShellTool +from app.tool.sandbox.sb_vision_tool import SandboxVisionTool class SandboxManus(ToolCallAgent): diff --git a/app/daytona/api.py b/app/daytona/api.py deleted file mode 100644 index e1fdc16..0000000 --- a/app/daytona/api.py +++ /dev/null @@ -1,468 +0,0 @@ -import os -import urllib.parse -from typing import Optional - -from fastapi import APIRouter, Depends, File, Form, HTTPException, Request, UploadFile -from fastapi.responses import Response -from pydantic import BaseModel -from sandbox.sandbox import delete_sandbox, get_or_start_sandbox -from services.supabase import DBConnection -from utils.auth_utils import get_optional_user_id -from utils.logger import logger - - -# Initialize shared resources -router = APIRouter(tags=["sandbox"]) -db = None - - -def initialize(_db: DBConnection): - """Initialize the sandbox API with resources from the main API.""" - global db - db = _db - logger.info("Initialized sandbox API with database connection") - - -class FileInfo(BaseModel): - """Model for file information""" - - name: str - path: str - is_dir: bool - size: int - mod_time: str - permissions: Optional[str] = None - - -def normalize_path(path: str) -> str: - """ - Normalize a path to ensure proper UTF-8 encoding and handling. - - Args: - path: The file path, potentially containing URL-encoded characters - - Returns: - Normalized path with proper UTF-8 encoding - """ - try: - # First, ensure the path is properly URL-decoded - decoded_path = urllib.parse.unquote(path) - - # Handle Unicode escape sequences like \u0308 - try: - # Replace Python-style Unicode escapes (\u0308) with actual characters - # This handles cases where the Unicode escape sequence is part of the URL - import re - - unicode_pattern = re.compile(r"\\u([0-9a-fA-F]{4})") - - def replace_unicode(match): - hex_val = match.group(1) - return chr(int(hex_val, 16)) - - decoded_path = unicode_pattern.sub(replace_unicode, decoded_path) - except Exception as unicode_err: - logger.warning( - f"Error processing Unicode escapes in path '{path}': {str(unicode_err)}" - ) - - logger.debug(f"Normalized path from '{path}' to '{decoded_path}'") - return decoded_path - except Exception as e: - logger.error(f"Error normalizing path '{path}': {str(e)}") - return path # Return original path if decoding fails - - -async def verify_sandbox_access(client, sandbox_id: str, user_id: Optional[str] = None): - """ - Verify that a user has access to a specific sandbox based on account membership. - - Args: - client: The Supabase client - sandbox_id: The sandbox ID to check access for - user_id: The user ID to check permissions for. Can be None for public resource access. - - Returns: - dict: Project data containing sandbox information - - Raises: - HTTPException: If the user doesn't have access to the sandbox or sandbox doesn't exist - """ - # Find the project that owns this sandbox - project_result = ( - await client.table("projects") - .select("*") - .filter("sandbox->>id", "eq", sandbox_id) - .execute() - ) - - if not project_result.data or len(project_result.data) == 0: - raise HTTPException(status_code=404, detail="Sandbox not found") - - project_data = project_result.data[0] - - if project_data.get("is_public"): - return project_data - - # For private projects, we must have a user_id - if not user_id: - raise HTTPException( - status_code=401, detail="Authentication required for this resource" - ) - - account_id = project_data.get("account_id") - - # Verify account membership - if account_id: - account_user_result = ( - await client.schema("basejump") - .from_("account_user") - .select("account_role") - .eq("user_id", user_id) - .eq("account_id", account_id) - .execute() - ) - if account_user_result.data and len(account_user_result.data) > 0: - return project_data - - raise HTTPException(status_code=403, detail="Not authorized to access this sandbox") - - -async def get_sandbox_by_id_safely(client, sandbox_id: str): - """ - Safely retrieve a sandbox object by its ID, using the project that owns it. - - Args: - client: The Supabase client - sandbox_id: The sandbox ID to retrieve - - Returns: - Sandbox: The sandbox object - - Raises: - HTTPException: If the sandbox doesn't exist or can't be retrieved - """ - # Find the project that owns this sandbox - project_result = ( - await client.table("projects") - .select("project_id") - .filter("sandbox->>id", "eq", sandbox_id) - .execute() - ) - - if not project_result.data or len(project_result.data) == 0: - logger.error(f"No project found for sandbox ID: {sandbox_id}") - raise HTTPException( - status_code=404, - detail="Sandbox not found - no project owns this sandbox ID", - ) - - # project_id = project_result.data[0]['project_id'] - # logger.debug(f"Found project {project_id} for sandbox {sandbox_id}") - - try: - # Get the sandbox - sandbox = await get_or_start_sandbox(sandbox_id) - # Extract just the sandbox object from the tuple (sandbox, sandbox_id, sandbox_pass) - # sandbox = sandbox_tuple[0] - - return sandbox - except Exception as e: - logger.error(f"Error retrieving sandbox {sandbox_id}: {str(e)}") - raise HTTPException( - status_code=500, detail=f"Failed to retrieve sandbox: {str(e)}" - ) - - -@router.post("/sandboxes/{sandbox_id}/files") -async def create_file( - sandbox_id: str, - path: str = Form(...), - file: UploadFile = File(...), - request: Request = None, - user_id: Optional[str] = Depends(get_optional_user_id), -): - """Create a file in the sandbox using direct file upload""" - # Normalize the path to handle UTF-8 encoding correctly - path = normalize_path(path) - - logger.info( - f"Received file upload request for sandbox {sandbox_id}, path: {path}, user_id: {user_id}" - ) - client = await db.client - - # Verify the user has access to this sandbox - await verify_sandbox_access(client, sandbox_id, user_id) - - try: - # Get sandbox using the safer method - sandbox = await get_sandbox_by_id_safely(client, sandbox_id) - - # Read file content directly from the uploaded file - content = await file.read() - - # Create file using raw binary content - sandbox.fs.upload_file(content, path) - logger.info(f"File created at {path} in sandbox {sandbox_id}") - - return {"status": "success", "created": True, "path": path} - except Exception as e: - logger.error(f"Error creating file in sandbox {sandbox_id}: {str(e)}") - raise HTTPException(status_code=500, detail=str(e)) - - -@router.get("/sandboxes/{sandbox_id}/files") -async def list_files( - sandbox_id: str, - path: str, - request: Request = None, - user_id: Optional[str] = Depends(get_optional_user_id), -): - """List files and directories at the specified path""" - # Normalize the path to handle UTF-8 encoding correctly - path = normalize_path(path) - - logger.info( - f"Received list files request for sandbox {sandbox_id}, path: {path}, user_id: {user_id}" - ) - client = await db.client - - # Verify the user has access to this sandbox - await verify_sandbox_access(client, sandbox_id, user_id) - - try: - # Get sandbox using the safer method - sandbox = await get_sandbox_by_id_safely(client, sandbox_id) - - # List files - files = sandbox.fs.list_files(path) - result = [] - - for file in files: - # Convert file information to our model - # Ensure forward slashes are used for paths, regardless of OS - full_path = ( - f"{path.rstrip('/')}/{file.name}" if path != "/" else f"/{file.name}" - ) - file_info = FileInfo( - name=file.name, - path=full_path, # Use the constructed path - is_dir=file.is_dir, - size=file.size, - mod_time=str(file.mod_time), - permissions=getattr(file, "permissions", None), - ) - result.append(file_info) - - logger.info(f"Successfully listed {len(result)} files in sandbox {sandbox_id}") - return {"files": [file.dict() for file in result]} - except Exception as e: - logger.error(f"Error listing files in sandbox {sandbox_id}: {str(e)}") - raise HTTPException(status_code=500, detail=str(e)) - - -@router.get("/sandboxes/{sandbox_id}/files/content") -async def read_file( - sandbox_id: str, - path: str, - request: Request = None, - user_id: Optional[str] = Depends(get_optional_user_id), -): - """Read a file from the sandbox""" - # Normalize the path to handle UTF-8 encoding correctly - original_path = path - path = normalize_path(path) - - logger.info( - f"Received file read request for sandbox {sandbox_id}, path: {path}, user_id: {user_id}" - ) - if original_path != path: - logger.info(f"Normalized path from '{original_path}' to '{path}'") - - client = await db.client - - # Verify the user has access to this sandbox - await verify_sandbox_access(client, sandbox_id, user_id) - - try: - # Get sandbox using the safer method - sandbox = await get_sandbox_by_id_safely(client, sandbox_id) - - # Read file directly - don't check existence first with a separate call - try: - content = sandbox.fs.download_file(path) - except Exception as download_err: - logger.error( - f"Error downloading file {path} from sandbox {sandbox_id}: {str(download_err)}" - ) - raise HTTPException( - status_code=404, detail=f"Failed to download file: {str(download_err)}" - ) - - # Return a Response object with the content directly - filename = os.path.basename(path) - logger.info(f"Successfully read file {filename} from sandbox {sandbox_id}") - - # Ensure proper encoding by explicitly using UTF-8 for the filename in Content-Disposition header - # This applies RFC 5987 encoding for the filename to support non-ASCII characters - encoded_filename = filename.encode("utf-8").decode("latin-1") - content_disposition = f"attachment; filename*=UTF-8''{encoded_filename}" - - return Response( - content=content, - media_type="application/octet-stream", - headers={"Content-Disposition": content_disposition}, - ) - except HTTPException: - # Re-raise HTTP exceptions without wrapping - raise - except Exception as e: - logger.error(f"Error reading file in sandbox {sandbox_id}: {str(e)}") - raise HTTPException(status_code=500, detail=str(e)) - - -@router.delete("/sandboxes/{sandbox_id}/files") -async def delete_file( - sandbox_id: str, - path: str, - request: Request = None, - user_id: Optional[str] = Depends(get_optional_user_id), -): - """Delete a file from the sandbox""" - # Normalize the path to handle UTF-8 encoding correctly - path = normalize_path(path) - - logger.info( - f"Received file delete request for sandbox {sandbox_id}, path: {path}, user_id: {user_id}" - ) - client = await db.client - - # Verify the user has access to this sandbox - await verify_sandbox_access(client, sandbox_id, user_id) - - try: - # Get sandbox using the safer method - sandbox = await get_sandbox_by_id_safely(client, sandbox_id) - - # Delete file - sandbox.fs.delete_file(path) - logger.info(f"File deleted at {path} in sandbox {sandbox_id}") - - return {"status": "success", "deleted": True, "path": path} - except Exception as e: - logger.error(f"Error deleting file in sandbox {sandbox_id}: {str(e)}") - raise HTTPException(status_code=500, detail=str(e)) - - -@router.delete("/sandboxes/{sandbox_id}") -async def delete_sandbox_route( - sandbox_id: str, - request: Request = None, - user_id: Optional[str] = Depends(get_optional_user_id), -): - """Delete an entire sandbox""" - logger.info( - f"Received sandbox delete request for sandbox {sandbox_id}, user_id: {user_id}" - ) - client = await db.client - - # Verify the user has access to this sandbox - await verify_sandbox_access(client, sandbox_id, user_id) - - try: - # Delete the sandbox using the sandbox module function - await delete_sandbox(sandbox_id) - - return {"status": "success", "deleted": True, "sandbox_id": sandbox_id} - except Exception as e: - logger.error(f"Error deleting sandbox {sandbox_id}: {str(e)}") - raise HTTPException(status_code=500, detail=str(e)) - - -# Should happen on server-side fully -@router.post("/project/{project_id}/sandbox/ensure-active") -async def ensure_project_sandbox_active( - project_id: str, - request: Request = None, - user_id: Optional[str] = Depends(get_optional_user_id), -): - """ - Ensure that a project's sandbox is active and running. - Checks the sandbox status and starts it if it's not running. - """ - logger.info( - f"Received ensure sandbox active request for project {project_id}, user_id: {user_id}" - ) - client = await db.client - - # Find the project and sandbox information - project_result = ( - await client.table("projects") - .select("*") - .eq("project_id", project_id) - .execute() - ) - - if not project_result.data or len(project_result.data) == 0: - logger.error(f"Project not found: {project_id}") - raise HTTPException(status_code=404, detail="Project not found") - - project_data = project_result.data[0] - - # For public projects, no authentication is needed - if not project_data.get("is_public"): - # For private projects, we must have a user_id - if not user_id: - logger.error(f"Authentication required for private project {project_id}") - raise HTTPException( - status_code=401, detail="Authentication required for this resource" - ) - - account_id = project_data.get("account_id") - - # Verify account membership - if account_id: - account_user_result = ( - await client.schema("basejump") - .from_("account_user") - .select("account_role") - .eq("user_id", user_id) - .eq("account_id", account_id) - .execute() - ) - if not (account_user_result.data and len(account_user_result.data) > 0): - logger.error( - f"User {user_id} not authorized to access project {project_id}" - ) - raise HTTPException( - status_code=403, detail="Not authorized to access this project" - ) - - try: - # Get sandbox ID from project data - sandbox_info = project_data.get("sandbox", {}) - if not sandbox_info.get("id"): - raise HTTPException( - status_code=404, detail="No sandbox found for this project" - ) - - sandbox_id = sandbox_info["id"] - - # Get or start the sandbox - logger.info(f"Ensuring sandbox is active for project {project_id}") - await get_or_start_sandbox(sandbox_id) - - logger.info( - f"Successfully ensured sandbox {sandbox_id} is active for project {project_id}" - ) - - return { - "status": "success", - "sandbox_id": sandbox_id, - "message": "Sandbox is active", - } - except Exception as e: - logger.error( - f"Error ensuring sandbox is active for project {project_id}: {str(e)}" - ) - raise HTTPException(status_code=500, detail=str(e)) diff --git a/app/daytona/sandbox.py b/app/daytona/sandbox.py index 6901a75..ff866ce 100644 --- a/app/daytona/sandbox.py +++ b/app/daytona/sandbox.py @@ -135,12 +135,12 @@ def create_sandbox(password: str, project_id: str = None): # Create the sandbox sandbox = daytona.create(params) - logger.debug(f"Sandbox created with ID: {sandbox.id}") + logger.info(f"Sandbox created with ID: {sandbox.id}") # Start supervisord in a session for new sandbox start_supervisord_session(sandbox) - logger.debug(f"Sandbox environment successfully initialized") + logger.info(f"Sandbox environment successfully initialized") return sandbox diff --git a/app/tool/sb_browser_tool.py b/app/tool/sandbox/sb_browser_tool.py similarity index 100% rename from app/tool/sb_browser_tool.py rename to app/tool/sandbox/sb_browser_tool.py diff --git a/app/tool/sb_files_tool.py b/app/tool/sandbox/sb_files_tool.py similarity index 100% rename from app/tool/sb_files_tool.py rename to app/tool/sandbox/sb_files_tool.py diff --git a/app/tool/sb_shell_tool.py b/app/tool/sandbox/sb_shell_tool.py similarity index 100% rename from app/tool/sb_shell_tool.py rename to app/tool/sandbox/sb_shell_tool.py diff --git a/app/tool/sb_vision_tool.py b/app/tool/sandbox/sb_vision_tool.py similarity index 100% rename from app/tool/sb_vision_tool.py rename to app/tool/sandbox/sb_vision_tool.py diff --git a/requirements.txt b/requirements.txt index aa7e6dc..8e9e136 100644 --- a/requirements.txt +++ b/requirements.txt @@ -40,3 +40,6 @@ crawl4ai~=0.6.3 huggingface-hub~=0.29.2 setuptools~=75.8.0 + +daytona==0.21.8 +structlog==25.4.0 diff --git a/tests/daytona/test_computer_use_tool.py b/tests/daytona/test_computer_use_tool.py deleted file mode 100644 index 0b359e5..0000000 --- a/tests/daytona/test_computer_use_tool.py +++ /dev/null @@ -1,25 +0,0 @@ -import asyncio - -from app.daytona.sandbox import create_sandbox -from app.tool.computer_use_tool import ComputerUseTool - - -async def main(): - # 创建沙箱和工具 - sandbox = create_sandbox(password="123456") - base_url = sandbox.get_preview_link(8000) - print(f"Sandbox base URL: {base_url}") - - print(f"Sandbox ID: {sandbox.id}") - computer_tool = ComputerUseTool.create_with_sandbox(sandbox) - - # 执行截图操作 - result = await computer_tool.execute(action="screenshot") - print(result) - - # 清理资源(可选) - await computer_tool.cleanup() - - -if __name__ == "__main__": - asyncio.run(main()) # 运行异步主函数 diff --git a/tests/daytona/test_daytona.py b/tests/daytona/test_daytona.py deleted file mode 100644 index 692f740..0000000 --- a/tests/daytona/test_daytona.py +++ /dev/null @@ -1,79 +0,0 @@ -from daytona import CreateSandboxFromImageParams, Daytona, DaytonaConfig, Resources - - -# Using environment variables (DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET) -# daytona = Daytona() -# Using explicit configuration -config = DaytonaConfig(api_key="", api_url="https://app.daytona.io/api", target="us") -daytona = Daytona(config) -params = CreateSandboxFromImageParams( - image="", - # image=Image.debian_slim("3.12"), - public=True, - labels=None, - env_vars={ - "CHROME_PERSISTENT_SESSION": "true", - "RESOLUTION": "1024x768x24", - "RESOLUTION_WIDTH": "1024", - "RESOLUTION_HEIGHT": "768", - "VNC_PASSWORD": "123456", - "ANONYMIZED_TELEMETRY": "false", - "CHROME_PATH": "", - "CHROME_USER_DATA": "", - "CHROME_DEBUGGING_PORT": "9222", - "CHROME_DEBUGGING_HOST": "localhost", - "CHROME_CDP": "", - }, - resources=Resources( - cpu=1, - memory=1, - disk=1, - ), - auto_stop_interval=15, - auto_archive_interval=24 * 60, -) -# Create the sandbox -sandbox = daytona.create(params) -print(f"Sandbox created with ID: {sandbox.id}") - - -# from daytona import Daytona - -# def main(): -# # Initialize the SDK (uses environment variables by default) -# daytona = Daytona(config) - -# # Create a new sandbox -# sandbox = daytona.create() - -# # Execute a command -# response = sandbox.process.exec("echo 'Hello, World!'") -# print(response.result) - -# if __name__ == "__main__": -# main() -# from daytona import Daytona, DaytonaConfig - -# Define the configuration - -# config = DaytonaConfig(api_key="") - -# # Initialize the Daytona client - -# daytona = Daytona(config) - -# # Create the Sandbox instance - -# sandbox = daytona.create() - -# # Run the code securely inside the Sandbox - -# response = sandbox.process.code_run('print("Hello World from code!")') -# if response.exit_code != 0: -# print(f"Error: {response.exit_code} {response.result}") -# else: -# print(response.result) - -# Clean up - -# sandbox.delete() diff --git a/tests/daytona/test_sb_browser_use.py b/tests/daytona/test_sb_browser_use.py deleted file mode 100644 index af28980..0000000 --- a/tests/daytona/test_sb_browser_use.py +++ /dev/null @@ -1,82 +0,0 @@ -import asyncio - -from app.daytona.sandbox import create_sandbox -from app.tool.sb_browser_tool import SandboxBrowserTool - - -async def main(): - # 创建沙箱和工具 - sandbox = create_sandbox(password="123456") - # config = DaytonaConfig( - # api_key="", - # api_url="https://app.daytona.io/api", - # target="us" - # ) - # daytona = Daytona(config) - # sandbox = daytona.find_one("201415a9-28ad-4b6d-8756-13b1e34a70c3") - # if sandbox.state == "archived" or sandbox.state == "stopped": - # logger.info(f"Sandbox is in {sandbox.state} state. Starting...") - # try: - # daytona.start(sandbox) - # start_supervisord_session(sandbox) - # # Wait a moment for the sandbox to initialize - # # sleep(5) - # # Refresh sandbox state after starting - # # sandbox = daytona.get(sandbox.id) - # except Exception as e: - # logger.error(f"Error starting sandbox: {e}") - # raise e - - # sandbox.start() - vnc_link = sandbox.get_preview_link(6080) - website_link = sandbox.get_preview_link(8080) - computer_link = sandbox.get_preview_link(8000) - print(f"VNC Link: {vnc_link}") - print(f"Website Link: {website_link}") - print(f"Computer Link: {computer_link}") - # sandbox.start() - # base_url=sandbox.get_preview_link(8000) - # print(f"Sandbox base URL: {base_url}") - - # print(f"Sandbox ID: {sandbox.id}") - tool = SandboxBrowserTool(sandbox) - - # # 执行截图操作 - result, tooresult = await tool.execute( - action="navigate_to", url="https://www.github.com" - ) - print(result) - - # endpoint = "navigate_to" - # method = "POST" - # params = { - # "url": "https://www.google.com" - # } - # url = f"http://localhost:8003/api/automation/{endpoint}" - # curl_cmd = f"curl -s -X {method} '{url}' -H 'Content-Type: application/json'" - # json_data = json.dumps(params) - # curl_cmd += f" -d '{json_data}'" - # logger.debug(f"Executing curl command: {curl_cmd}") - # response = sandbox.process.exec(curl_cmd, timeout=30) - # print(f"Response: {response}") - - # response = sandbox.process.exec("ls -la") - # print(response.result) - # 清理资源(可选) - # await computer_tool.cleanup() - - -if __name__ == "__main__": - asyncio.run(main()) # 运行异步主函数 - # await computer_tool.cleanup() - -if __name__ == "__main__": - asyncio.run(main()) # 运行异步主函数 - # await computer_tool.cleanup() - -if __name__ == "__main__": - asyncio.run(main()) # 运行异步主函数 - # await computer_tool.cleanup() - -if __name__ == "__main__": - asyncio.run(main()) # 运行异步主函数 diff --git a/tests/daytona/test_sb_files_tool.py b/tests/daytona/test_sb_files_tool.py deleted file mode 100644 index d507658..0000000 --- a/tests/daytona/test_sb_files_tool.py +++ /dev/null @@ -1,43 +0,0 @@ -import asyncio - -from app.daytona.sandbox import create_sandbox -from app.tool.sb_files_tool import SandboxFilesTool - - -async def main(): - # 创建沙箱和工具 - sandbox = create_sandbox(password="123456") - # base_url=sandbox.get_preview_link(8000) - # print(f"Sandbox base URL: {base_url}") - - print(f"Sandbox ID: {sandbox.id}") - - vnc_link = sandbox.get_preview_link(6080) - website_link = sandbox.get_preview_link(8080) - print(f"VNC Link: {vnc_link}") - print(f"Website Link: {website_link}") - - sb_files_tool = SandboxFilesTool(sandbox) - - # 执行创建文件操作 - result = await sb_files_tool.execute( - action="create_file", file_path="src/a.txt", file_contents="aaaaa1111" - ) - print(result) - # 执行字符串替换操作 - # result = await sb_files_tool.execute(action="str_replace", file_path="src/a.txt", old_str="aaaaa", new_str="bbbbb") - # print(result) - # 执行全文件重写操作 - result = await sb_files_tool.execute( - action="full_file_rewrite", file_path="src/a.txt", file_contents="1234567" - ) - print(result) - # 执行删除文件操作 - # result = await sb_files_tool.execute(action="delete_file", file_path="src/a.txt") - # print(result) - # 清理资源(可选) - # await sb_shell_tool.cleanup() - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/tests/daytona/test_sb_shell_tools.py b/tests/daytona/test_sb_shell_tools.py deleted file mode 100644 index 8c69f51..0000000 --- a/tests/daytona/test_sb_shell_tools.py +++ /dev/null @@ -1,31 +0,0 @@ -import asyncio - -from app.daytona.sandbox import create_sandbox -from app.tool.sb_shell_tool import SandboxShellTool - - -async def main(): - # 创建沙箱和工具 - sandbox = create_sandbox(password="123456") - # base_url=sandbox.get_preview_link(8000) - # print(f"Sandbox base URL: {base_url}") - - print(f"Sandbox ID: {sandbox.id}") - - vnc_link = sandbox.get_preview_link(6080) - website_link = sandbox.get_preview_link(8080) - print(f"VNC Link: {vnc_link}") - print(f"Website Link: {website_link}") - sb_shell_tool = SandboxShellTool(sandbox) - - # 执行截图操作 - result = await sb_shell_tool.execute(action="execute_command", command="pwd") - print(result) - - # 清理资源(可选) - # await sb_shell_tool.cleanup() - - -if __name__ == "__main__": - print("123") - asyncio.run(main()) diff --git a/tests/daytona/test_sb_vision_tool.py b/tests/daytona/test_sb_vision_tool.py deleted file mode 100644 index c06a51c..0000000 --- a/tests/daytona/test_sb_vision_tool.py +++ /dev/null @@ -1,40 +0,0 @@ -import asyncio - -from app.daytona.sandbox import create_sandbox -from app.tool.sb_shell_tool import SandboxShellTool -from app.tool.sb_vision_tool import SandboxVisionTool - - -async def main(): - # 创建沙箱和工具 - sandbox = create_sandbox(password="123456") - # base_url=sandbox.get_preview_link(8000) - # print(f"Sandbox base URL: {base_url}") - - print(f"Sandbox ID: {sandbox.id}") - - vnc_link = sandbox.get_preview_link(6080) - website_link = sandbox.get_preview_link(8080) - print(f"VNC Link: {vnc_link}") - print(f"Website Link: {website_link}") - sb_shell_tool = SandboxShellTool(sandbox) - sb_vision_tool = SandboxVisionTool(sandbox) - - # 执行终端命令 - result = await sb_shell_tool.execute( - action="execute_command", - command="curl -O http://img.netbian.com/file/2025/0716/091412RIFD9.jpg", - ) - print(result) - # 执行see_image操作 - result = await sb_vision_tool.execute( - action="see_image", file_path="091412RIFD9.jpg" - ) - print(result) - - # 清理资源(可选) - # await sb_shell_tool.cleanup() - - -if __name__ == "__main__": - asyncio.run(main())