-
Notifications
You must be signed in to change notification settings - Fork 3k
Open
Labels
tools[Component] This issue is related to tools[Component] This issue is related to tools
Description
Add exec-sandbox code executor (self-hosted QEMU microVMs)
Summary
Proposing exec-sandbox as a new BaseCodeExecutor backend. It runs code in ephemeral QEMU microVMs with hardware-level isolation (KVM on Linux, HVF on macOS) — self-hosted, no cloud account needed.
Why
- Self-hosted — ContainerCodeExecutor needs Docker, GkeCodeExecutor needs GKE, VertexAiCodeExecutor needs Vertex. exec-sandbox runs on bare metal with just QEMU. Data never leaves the machine — relevant for customer data privacy, regulated environments, and cheaper at scale.
- macOS + Linux — HVF on macOS, KVM on Linux. Same codebase for dev and prod.
- Fast — ~1-2ms from warm pool, ~200ms from memory snapshots.
- Stronger isolation than containers — Hardware-level VM boundary vs Docker process isolation.
- Apache-2.0
How it maps
exec-sandbox is a Python library with an async API. A BaseCodeExecutor subclass bridges async → sync, following the same pattern as ContainerCodeExecutor:
import asyncio
from exec_sandbox import Scheduler
class ExecSandboxCodeExecutor(BaseCodeExecutor):
stateful: bool = True
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._loop = asyncio.new_event_loop()
self._scheduler = self._loop.run_until_complete(Scheduler().__aenter__())
self._sessions: dict[str, Session] = {}
def execute_code(self, invocation_context, code_execution_input):
# Reuse session for stateful execution
eid = code_execution_input.execution_id
if eid and eid in self._sessions:
session = self._sessions[eid]
else:
session = self._loop.run_until_complete(
self._scheduler.session(language="python")
)
if eid:
self._sessions[eid] = session
result = self._loop.run_until_complete(session.exec(code_execution_input.code))
return CodeExecutionResult(
stdout=result.stdout,
stderr=result.stderr,
)Usage:
agent = LlmAgent(
code_executor=ExecSandboxCodeExecutor(),
...
)Open questions
- Async/sync bridge — exec-sandbox is fully async. The sketch uses a dedicated event loop. A background-thread loop would be safer if called from an existing async context.
- File I/O —
CodeExecutionInput.input_filesandCodeExecutionResult.output_filescould use exec-sandbox's nativewrite_file/read_fileAPIs instead of writing to a shared volume. - Shipping — External package (
exec-sandbox[adk]extra) vs upstream incode_executors/following the GkeCodeExecutor pattern from PR feat(code_executors): Add GkeCodeExecutor for sandboxed code execution on GKE #1629.
Links
Happy to submit a PR if there's interest.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
tools[Component] This issue is related to tools[Component] This issue is related to tools