from shipyard import ShipyardClient, Spec from astrbot.api import logger from ..olayer import FileSystemComponent, PythonComponent, ShellComponent from .base import ComputerBooter class ShipyardBooter(ComputerBooter): def __init__( self, endpoint_url: str, access_token: str, ttl: int = 3600, session_num: int = 10, ) -> None: self._sandbox_client = ShipyardClient( endpoint_url=endpoint_url, access_token=access_token ) self._ttl = ttl self._session_num = session_num async def boot(self, session_id: str) -> None: ship = await self._sandbox_client.create_ship( ttl=self._ttl, spec=Spec(cpus=1.0, memory="512m"), max_session_num=self._session_num, session_id=session_id, ) logger.info(f"Got sandbox ship: {ship.id} for session: {session_id}") self._ship = ship async def shutdown(self) -> None: logger.info("[Computer] Shipyard booter shutdown.") @property def fs(self) -> FileSystemComponent: return self._ship.fs @property def python(self) -> PythonComponent: return self._ship.python @property def shell(self) -> ShellComponent: return self._ship.shell async def upload_file(self, path: str, file_name: str) -> dict: """Upload file to sandbox""" result = await self._ship.upload_file(path, file_name) logger.info("[Computer] File uploaded to Shipyard sandbox: %s", file_name) return result async def download_file(self, remote_path: str, local_path: str): """Download file from sandbox.""" result = await self._ship.download_file(remote_path, local_path) logger.info( "[Computer] File downloaded from Shipyard sandbox: %s -> %s", remote_path, local_path, ) return result async def available(self) -> bool: """Check if the sandbox is available.""" try: ship_id = self._ship.id data = await self._sandbox_client.get_ship(ship_id) if not data: logger.info( "[Computer] Shipyard sandbox health check: id=%s, healthy=False (no data)", ship_id, ) return False health = bool(data.get("status", 0) == 1) logger.info( "[Computer] Shipyard sandbox health check: id=%s, healthy=%s", ship_id, health, ) return health except Exception as e: logger.error(f"Error checking Shipyard sandbox availability: {e}") return False