Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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=""
)
Expand Down
60 changes: 38 additions & 22 deletions app/daytona/sandbox.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time
from typing import Optional

from daytona import (
CreateSandboxFromImageParams,
Expand All @@ -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}")

Expand Down Expand Up @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -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:
Expand Down
14 changes: 6 additions & 8 deletions app/daytona/tool_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@
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


# 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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions config/config.example-daytona.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down