google / google/adk-python

Add exec-sandbox code executor (self-hosted QEMU microVMs)

Abierto
#4,643 1 comentario 0 reacciones 2 asignados Reclamado por @xuanyang15 Ver en GitHub
needs review tools
Lenguaje dominante
Python
Estrellas
21.5k
Forks
4k
Merge medio
1 d 14 h
PR fusionados (30 d)
37

Descripción

# Add exec-sandbox code executor (self-hosted QEMU microVMs)

## Summary

Proposing [exec-sandbox](https://github.com/dualeai/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:

```python
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:

```python
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_files` and `CodeExecutionResult.output_files` could use exec-sandbox's native `write_file`/`read_file` APIs instead of writing to a shared volume.
- **Shipping** — External package (`exec-sandbox[adk]` extra) vs upstream in `code_executors/` following the GkeCodeExecutor pattern from PR #1629.

## Links

- [Repo](https://github.com/dualeai/exec-sandbox) · [PyPI](https://pypi.org/project/exec-sandbox/)
- Reference: `gke_code_executor.py` in `code_executors/` (same integration pattern)

Happy to submit a PR if there's interest.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.