From dab143f5f15cdbc1f8a55b8c51107d11f5afd02b Mon Sep 17 00:00:00 2001 From: Aniket Maurya Date: Wed, 6 May 2026 01:35:58 +0100 Subject: [PATCH] Serialize sandbox file operations --- src/celesto/integrations/openai_agents/hosted.py | 14 ++++++++------ src/celesto/integrations/openai_agents/smolvm.py | 15 +++++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/celesto/integrations/openai_agents/hosted.py b/src/celesto/integrations/openai_agents/hosted.py index 6d9a370..a32109d 100644 --- a/src/celesto/integrations/openai_agents/hosted.py +++ b/src/celesto/integrations/openai_agents/hosted.py @@ -57,6 +57,7 @@ def __init__(self, *, state: CelestoSandboxSessionState, client: Celesto) -> Non self.state = state self._client = client self._running = False + self._command_lock = asyncio.Lock() @classmethod def from_state( @@ -95,12 +96,13 @@ async def _run_guest(self, command: str, *, timeout: float | None = None) -> dic "No Celesto computer is ready yet. Start the session with " "`async with session:` before running commands." ) - return await asyncio.to_thread( - self._client.computers.exec, - self.state.computer_id, - command, - timeout=timeout_seconds(timeout), - ) + async with self._command_lock: + return await asyncio.to_thread( + self._client.computers.exec, + self.state.computer_id, + command, + timeout=timeout_seconds(timeout), + ) async def _delete_backend(self) -> None: if self.state.computer_id is None: diff --git a/src/celesto/integrations/openai_agents/smolvm.py b/src/celesto/integrations/openai_agents/smolvm.py index ca04139..5169a68 100644 --- a/src/celesto/integrations/openai_agents/smolvm.py +++ b/src/celesto/integrations/openai_agents/smolvm.py @@ -65,6 +65,7 @@ def __init__(self, *, state: SmolVMSandboxSessionState) -> None: self.state = state self._vm: Any | None = None self._running = False + self._command_lock = asyncio.Lock() @classmethod def from_state(cls, state: SmolVMSandboxSessionState) -> "SmolVMSandboxSession": @@ -111,11 +112,12 @@ async def _shutdown_backend(self) -> None: async def _run_guest(self, command: str, *, timeout: float | None = None) -> dict[str, Any]: vm = self._connect_or_create_vm() - result = await asyncio.to_thread( - vm.run, - command, - timeout=timeout_seconds(timeout), - ) + async with self._command_lock: + result = await asyncio.to_thread( + vm.run, + command, + timeout=timeout_seconds(timeout), + ) return {"exit_code": result.exit_code, "stdout": result.stdout, "stderr": result.stderr} async def _resolve_exposed_port(self, port: int) -> ExposedPortEndpoint: @@ -138,7 +140,8 @@ async def write( tmp_path = Path(tmp.name) try: vm = self._connect_or_create_vm() - await asyncio.to_thread(vm.upload_file, tmp_path, workspace_path.as_posix()) + async with self._command_lock: + await asyncio.to_thread(vm.upload_file, tmp_path, workspace_path.as_posix()) finally: tmp_path.unlink(missing_ok=True)