diff --git a/app/config.py b/app/config.py index a881e2a5e..74fd33b48 100644 --- a/app/config.py +++ b/app/config.py @@ -106,7 +106,8 @@ class SandboxSettings(BaseModel): class DaytonaSettings(BaseModel): - daytona_api_key: str + use_daytona: bool = Field(False, description="Whether to use the daytona") + daytona_api_key: Optional[str] = Field(None, description="Daytona API key") daytona_server_url: Optional[str] = Field( "https://app.daytona.io/api", description="" ) diff --git a/app/daytona/sandbox.py b/app/daytona/sandbox.py index 8970b9cef..da4d92f91 100644 --- a/app/daytona/sandbox.py +++ b/app/daytona/sandbox.py @@ -1,4 +1,5 @@ import time +from typing import Optional from daytona import ( CreateSandboxFromImageParams, @@ -14,36 +15,40 @@ from app.utils.logger import logger -# load_dotenv() daytona_settings = config.daytona -logger.info("Initializing Daytona sandbox configuration") -daytona_config = DaytonaConfig( - api_key=daytona_settings.daytona_api_key, - server_url=daytona_settings.daytona_server_url, - target=daytona_settings.daytona_target, -) +daytona: Optional[Daytona] = None +daytona_config: Optional[DaytonaConfig] = None -if daytona_config.api_key: - logger.info("Daytona API key configured successfully") -else: - logger.warning("No Daytona API key found in environment variables") +if daytona_settings.use_daytona: + logger.info("Daytona is enabled. Initializing Daytona sandbox configuration.") -if daytona_config.server_url: - logger.info(f"Daytona server URL set to: {daytona_config.server_url}") -else: - logger.warning("No Daytona server URL found in environment variables") - -if daytona_config.target: - logger.info(f"Daytona target set to: {daytona_config.target}") + if not daytona_settings.daytona_api_key: + logger.error( + "Daytona is enabled, but no Daytona API key is configured. Daytona features will be unavailable." + ) + else: + daytona_config = DaytonaConfig( + api_key=daytona_settings.daytona_api_key, + server_url=daytona_settings.daytona_server_url, + target=daytona_settings.daytona_target, + ) + logger.info("Daytona API key configured successfully") + if daytona_config.server_url: + logger.info(f"Daytona server URL set to: {daytona_config.server_url}") + if daytona_config.target: + logger.info(f"Daytona target set to: {daytona_config.target}") + + daytona = Daytona(daytona_config) + logger.info("Daytona client initialized") else: - logger.warning("No Daytona target found in environment variables") - -daytona = Daytona(daytona_config) -logger.info("Daytona client initialized") + logger.info("Daytona is disabled. Skipping Daytona client initialization.") async def get_or_start_sandbox(sandbox_id: str): """Retrieve a sandbox by ID, check its state, and start it if needed.""" + if not daytona: + logger.warning("Daytona is not enabled. Cannot get or start sandbox.") + return None logger.info(f"Getting or starting sandbox with ID: {sandbox_id}") @@ -79,6 +84,10 @@ async def get_or_start_sandbox(sandbox_id: str): def start_supervisord_session(sandbox: Sandbox): """Start supervisord in a session.""" + if not daytona: + logger.warning("Daytona is not enabled. Cannot start supervisord session.") + return + session_id = "supervisord-session" try: logger.info(f"Creating session {session_id} for supervisord") @@ -101,6 +110,9 @@ def start_supervisord_session(sandbox: Sandbox): def create_sandbox(password: str, project_id: str = None): """Create a new sandbox with all required services configured and running.""" + if not daytona: + logger.warning("Daytona is not enabled. Cannot create sandbox.") + return None logger.info("Creating new Daytona sandbox environment") logger.info("Configuring sandbox with browser-use image and environment variables") @@ -149,6 +161,10 @@ def create_sandbox(password: str, project_id: str = None): async def delete_sandbox(sandbox_id: str): """Delete a sandbox by its ID.""" + if not daytona: + logger.warning("Daytona is not enabled. Cannot delete sandbox.") + return False + logger.info(f"Deleting sandbox with ID: {sandbox_id}") try: diff --git a/app/daytona/tool_base.py b/app/daytona/tool_base.py index 043578a9a..2447799d0 100644 --- a/app/daytona/tool_base.py +++ b/app/daytona/tool_base.py @@ -2,11 +2,11 @@ from datetime import datetime from typing import Any, ClassVar, Dict, Optional -from daytona import Daytona, DaytonaConfig, Sandbox, SandboxState +from daytona import Sandbox, SandboxState from pydantic import Field from app.config import config -from app.daytona.sandbox import create_sandbox, start_supervisord_session +from app.daytona.sandbox import create_sandbox, daytona, start_supervisord_session from app.tool.base import BaseTool from app.utils.files_utils import clean_path from app.utils.logger import logger @@ -14,12 +14,6 @@ # load_dotenv() daytona_settings = config.daytona -daytona_config = DaytonaConfig( - api_key=daytona_settings.daytona_api_key, - server_url=daytona_settings.daytona_server_url, - target=daytona_settings.daytona_target, -) -daytona = Daytona(daytona_config) @dataclass @@ -70,6 +64,9 @@ class Config: async def _ensure_sandbox(self) -> Sandbox: """Ensure we have a valid sandbox instance, retrieving it from the project if needed.""" + if not daytona: + raise RuntimeError("Daytona is not enabled. Sandbox tools are unavailable.") + if self._sandbox is None: # Get or start the sandbox try: @@ -136,3 +133,4 @@ def clean_path(self, path: str) -> str: cleaned_path = clean_path(path, self.workspace_path) logger.debug(f"Cleaned path: {path} -> {cleaned_path}") return cleaned_path + return cleaned_path diff --git a/config/config.example-daytona.toml b/config/config.example-daytona.toml index 10975df2e..888cb117f 100644 --- a/config/config.example-daytona.toml +++ b/config/config.example-daytona.toml @@ -97,6 +97,7 @@ temperature = 0.0 # Controls randomness for vision mode # Daytona configuration [daytona] +use_daytona = true daytona_api_key = "" #daytona_server_url = "https://app.daytona.io/api" #daytona_target = "us" #Daytona is currently available in the following regions:United States (us)、Europe (eu)