Skip to content

Commit 8e93473

Browse files
JoffrefcploujouxHugoch
authored
Add Blaxel support for remote code execution (#1791)
Co-authored-by: cploujoux <[email protected]> Co-authored-by: Hugo Larcher <[email protected]>
1 parent 4dbab6d commit 8e93473

File tree

12 files changed

+444
-24
lines changed

12 files changed

+444
-24
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ limitations under the License.
3434

3535
**Simplicity**: the logic for agents fits in ~1,000 lines of code (see [agents.py](https://github.com/huggingface/smolagents/blob/main/src/smolagents/agents.py)). We kept abstractions to their minimal shape above raw code!
3636

37-
🧑‍💻 **First-class support for Code Agents**. Our [`CodeAgent`](https://huggingface.co/docs/smolagents/reference/agents#smolagents.CodeAgent) writes its actions in code (as opposed to "agents being used to write code"). To make it secure, we support executing in sandboxed environments via [E2B](https://e2b.dev/), [Modal](https://modal.com/), Docker, or Pyodide+Deno WebAssembly sandbox.
37+
🧑‍💻 **First-class support for Code Agents**. Our [`CodeAgent`](https://huggingface.co/docs/smolagents/reference/agents#smolagents.CodeAgent) writes its actions in code (as opposed to "agents being used to write code"). To make it secure, we support executing in sandboxed environments via [Blaxel](https://blaxel.ai), [E2B](https://e2b.dev/), [Modal](https://modal.com/), Docker, or Pyodide+Deno WebAssembly sandbox.
3838

3939
🤗 **Hub integrations**: you can [share/pull tools or agents to/from the Hub](https://huggingface.co/docs/smolagents/reference/tools#smolagents.Tool.from_hub) for instant sharing of the most efficient agents!
4040

@@ -239,7 +239,7 @@ Writing actions as code snippets is demonstrated to work better than the current
239239

240240
Especially, since code execution can be a security concern (arbitrary code execution!), we provide options at runtime:
241241
- a secure python interpreter to run code more safely in your environment (more secure than raw code execution but still risky)
242-
- a sandboxed environment using [E2B](https://e2b.dev/) or Docker (removes the risk to your own system).
242+
- a sandboxed environment using [Blaxel](https://blaxel.ai), [E2B](https://e2b.dev/), or Docker (removes the risk to your own system).
243243

244244
Alongside [`CodeAgent`](https://huggingface.co/docs/smolagents/reference/agents#smolagents.CodeAgent), we also provide the standard [`ToolCallingAgent`](https://huggingface.co/docs/smolagents/reference/agents#smolagents.ToolCallingAgent) which writes actions as JSON/text blobs. You can pick whichever style best suits your use case.
245245

@@ -265,7 +265,7 @@ This comparison shows that open-source models can now take on the best closed mo
265265
## Security
266266

267267
Security is a critical consideration when working with code-executing agents. Our library provides:
268-
- Sandboxed execution options using [E2B](https://e2b.dev/), [Modal](https://modal.com/), Docker, or Pyodide+Deno WebAssembly sandbox
268+
- Sandboxed execution options using [Blaxel](https://blaxel.ai), [E2B](https://e2b.dev/), [Modal](https://modal.com/), Docker, or Pyodide+Deno WebAssembly sandbox
269269
- Best practices for running agent code securely
270270

271271
For security policies, vulnerability reporting, and more information on secure agent execution, please see our [Security Policy](SECURITY.md).

docs/source/en/guided_tour.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ This could also be authorized by using `numpy.*`, which will allow `numpy` as we
8585

8686
The execution will stop at any code trying to perform an illegal operation or if there is a regular Python error with the code generated by the agent.
8787

88-
You can also use [E2B code executor](https://e2b.dev/docs#what-is-e2-b) or Docker instead of a local Python interpreter. For E2B, first [set the `E2B_API_KEY` environment variable](https://e2b.dev/dashboard?tab=keys) and then pass `executor_type="e2b"` upon agent initialization. For Docker, pass `executor_type="docker"` during initialization.
88+
You can also use [Blaxel](https://blaxel.ai), [E2B](https://e2b.dev/docs#what-is-e2-b), or Docker instead of a local Python interpreter. For Blaxel, first [set the `BL_API_KEY` and `BL_WORKSPACE` environment variables](https://app.blaxel.ai/profile/security) and then pass `executor_type="blaxel"` upon agent initialization. For E2B, first [set the `E2B_API_KEY` environment variable](https://e2b.dev/dashboard?tab=keys) and then pass `executor_type="e2b"`. For Docker, pass `executor_type="docker"`.
8989

9090

9191
> [!TIP]

docs/source/en/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Key features of `smolagents` include:
1212

1313
**Simplicity**: The logic for agents fits in ~thousand lines of code. We kept abstractions to their minimal shape above raw code!
1414

15-
🧑‍💻 **First-class support for Code Agents**: [`CodeAgent`](reference/agents#smolagents.CodeAgent) writes its actions in code (as opposed to "agents being used to write code") to invoke tools or perform computations, enabling natural composability (function nesting, loops, conditionals). To make it secure, we support [executing in sandboxed environment](tutorials/secure_code_execution) via [E2B](https://e2b.dev/) or via Docker.
15+
🧑‍💻 **First-class support for Code Agents**: [`CodeAgent`](reference/agents#smolagents.CodeAgent) writes its actions in code (as opposed to "agents being used to write code") to invoke tools or perform computations, enabling natural composability (function nesting, loops, conditionals). To make it secure, we support [executing in sandboxed environment](tutorials/secure_code_execution) via [Blaxel](https://blaxel.ai), [E2B](https://e2b.dev/), or Docker.
1616

1717
📡 **Common Tool-Calling Agent Support**: In addition to CodeAgents, [`ToolCallingAgent`](reference/agents#smolagents.ToolCallingAgent) supports usual JSON/text-based tool-calling for scenarios where that paradigm is preferred.
1818

docs/source/en/installation.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,24 +180,32 @@ Extras for handling different types of media and input:
180180
Extras for executing code remotely:
181181
<hfoptions id="installation">
182182
<hfoption id="pip">
183-
- **docker**: Add support for executing code in Docker containers.
183+
- **blaxel**: Add support for Blaxel sandboxes - fast-launching VMs with hibernation (recommended).
184184
```bash
185-
pip install "smolagents[docker]"
185+
pip install "smolagents[blaxel]"
186186
```
187187
- **e2b**: Enable E2B support for remote execution.
188188
```bash
189189
pip install "smolagents[e2b]"
190190
```
191+
- **docker**: Add support for executing code in Docker containers.
192+
```bash
193+
pip install "smolagents[docker]"
194+
```
191195
</hfoption>
192196
<hfoption id="uv">
193-
- **docker**: Add support for executing code in Docker containers.
197+
- **blaxel**: Add support for Blaxel sandboxes - fast-launching VMs with hibernation (recommended).
194198
```bash
195-
uv pip install "smolagents[docker]"
199+
uv pip install "smolagents[blaxel]"
196200
```
197201
- **e2b**: Enable E2B support for remote execution.
198202
```bash
199203
uv pip install "smolagents[e2b]"
200204
```
205+
- **docker**: Add support for executing code in Docker containers.
206+
```bash
207+
uv pip install "smolagents[docker]"
208+
```
201209
</hfoption>
202210
</hfoptions>
203211

docs/source/en/reference/agents.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ Smolagents use memory to store information across multiple steps.
6767

6868
[[autodoc]] smolagents.remote_executors.RemotePythonExecutor
6969

70+
#### BlaxelExecutor
71+
72+
[[autodoc]] smolagents.remote_executors.BlaxelExecutor
73+
7074
#### E2BExecutor
7175

7276
[[autodoc]] smolagents.remote_executors.E2BExecutor

docs/source/en/tutorials/secure_code_execution.md

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,46 @@ When working with AI agents that execute code, security is paramount. There are
118118

119119
![Sandbox approaches comparison](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/sandboxed_execution.png)
120120

121-
1. **Running individual code snippets in a sandbox**: This approach (left side of diagram) only executes the agent-generated Python code snippets in a sandbox while keeping the rest of the agentic system in your local environment. It's simpler to set up using `executor_type="e2b"`, `executor_type="modal"`, or
121+
1. **Running individual code snippets in a sandbox**: This approach (left side of diagram) only executes the agent-generated Python code snippets in a sandbox while keeping the rest of the agentic system in your local environment. It's simpler to set up using `executor_type="blaxel"`, `executor_type="e2b"`, `executor_type="modal"`, or
122122
`executor_type="docker"`, but it doesn't support multi-agents and still requires passing state data between your environment and the sandbox.
123123

124124
2. **Running the entire agentic system in a sandbox**: This approach (right side of diagram) runs the entire agentic system, including the agent, model, and tools, within a sandbox environment. This provides better isolation but requires more manual setup and may require passing sensitive credentials (like API keys) to the sandbox environment.
125125

126126
This guide describes how to set up and use both types of sandbox approaches for your agent applications.
127127

128+
### Blaxel setup
129+
130+
#### Installation
131+
132+
1. Create a Blaxel account at [blaxel.ai](https://blaxel.ai)
133+
2. Install the required packages:
134+
```bash
135+
pip install 'smolagents[blaxel]'
136+
```
137+
138+
#### Running your agent with Blaxel: quick start
139+
140+
We provide a simple way to use a Blaxel Sandbox: simply add `executor_type="blaxel"` to the agent initialization, as follows:
141+
142+
```py
143+
from smolagents import InferenceClientModel, CodeAgent
144+
145+
with CodeAgent(model=InferenceClientModel(), tools=[], executor_type="blaxel") as agent:
146+
agent.run("Can you give me the 100th Fibonacci number?")
147+
```
148+
149+
> [!TIP]
150+
> Using the agent as a context manager (with the `with` statement) ensures that the Blaxel sandbox is cleaned up immediately after the agent completes its task.
151+
> Alternatively, you can manually call the agent's `cleanup()` method.
152+
153+
This solution sends the agent state to the server at the start of each `agent.run()`.
154+
Then the models are called from the local environment, but the generated code will be sent to the sandbox for execution, and only the output will be returned.
155+
156+
Blaxel provides fast-launching virtual machines that start from hibernation in under 25ms and scale back to zero after inactivity while maintaining memory state, making it an excellent choice for agent applications that require quick, secure code execution.
157+
158+
> [!TIP]
159+
> For even stronger security isolation, you can host your entire agent remotely on Blaxel. This provides complete sandboxing of the agent, model, and tools. See the [Blaxel agent hosting documentation](https://docs.blaxel.ai/Agents/Develop-an-agent-py) for details.
160+
128161
### E2B setup
129162

130163
#### Installation
@@ -423,7 +456,7 @@ agent.run("Can you give me the 100th Fibonacci number?")
423456

424457
### Best practices for sandboxes
425458

426-
These key practices apply to both E2B and Docker sandboxes:
459+
These key practices apply to Blaxel, E2B, and Docker sandboxes:
427460

428461
- Resource management
429462
- Set memory and CPU limits
@@ -449,9 +482,10 @@ As illustrated in the diagram earlier, both sandboxing approaches have different
449482

450483
### Approach 1: Running just the code snippets in a sandbox
451484
- **Pros**:
452-
- Easier to set up with a simple parameter (`executor_type="e2b"` or `executor_type="docker"`)
485+
- Easier to set up with a simple parameter (`executor_type="blaxel"`, `executor_type="e2b"`, or `executor_type="docker"`)
453486
- No need to transfer API keys to the sandbox
454487
- Better protection for your local environment
488+
- Fast execution with Blaxel's hibernation technology (<25ms startup)
455489
- **Cons**:
456490
- Doesn't support multi-agents (managed agents)
457491
- Still requires transferring state between your environment and the sandbox

examples/sandboxed_execution.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
model = InferenceClientModel()
55

6+
# Blaxel executor example
7+
with CodeAgent(tools=[WebSearchTool()], model=model, executor_type="blaxel") as agent:
8+
output = agent.run("How many seconds would it take for a leopard at full speed to run through Pont des Arts?")
9+
print("Blaxel executor result:", output)
10+
611
# Docker executor example
712
with CodeAgent(tools=[WebSearchTool()], model=model, executor_type="docker") as agent:
813
output = agent.run("How many seconds would it take for a leopard at full speed to run through Pont des Arts?")

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ dependencies = [
2525
bedrock = [
2626
"boto3>=1.36.18"
2727
]
28+
blaxel = [
29+
"blaxel>=0.2.19",
30+
"websocket-client",
31+
]
2832
torch = [
2933
"torch",
3034
"torchvision",
@@ -86,7 +90,7 @@ vllm = [
8690
"torch"
8791
]
8892
all = [
89-
"smolagents[audio,docker,e2b,gradio,litellm,mcp,mlx-lm,modal,openai,telemetry,toolkit,transformers,vision,bedrock]",
93+
"smolagents[audio,blaxel,docker,e2b,gradio,litellm,mcp,mlx-lm,modal,openai,telemetry,toolkit,transformers,vision,bedrock]",
9094
]
9195
quality = [
9296
"ruff>=0.9.0",

src/smolagents/agents.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
LogLevel,
7676
Monitor,
7777
)
78-
from .remote_executors import DockerExecutor, E2BExecutor, ModalExecutor, WasmExecutor
78+
from .remote_executors import BlaxelExecutor, DockerExecutor, E2BExecutor, ModalExecutor, WasmExecutor
7979
from .tools import BaseTool, Tool, validate_tool_arguments
8080
from .utils import (
8181
AgentError,
@@ -1487,7 +1487,7 @@ class CodeAgent(MultiStepAgent):
14871487
additional_authorized_imports (`list[str]`, *optional*): Additional authorized imports for the agent.
14881488
planning_interval (`int`, *optional*): Interval at which the agent will run a planning step.
14891489
executor ([`PythonExecutor`], *optional*): Custom Python code executor. If not provided, a default executor will be created based on `executor_type`.
1490-
executor_type (`Literal["local", "e2b", "modal", "docker", "wasm"]`, default `"local"`): Type of code executor.
1490+
executor_type (`Literal["local", "blaxel", "e2b", "modal", "docker", "wasm"]`, default `"local"`): Type of code executor.
14911491
executor_kwargs (`dict`, *optional*): Additional arguments to pass to initialize the executor.
14921492
max_print_outputs_length (`int`, *optional*): Maximum length of the print outputs.
14931493
stream_outputs (`bool`, *optional*, default `False`): Whether to stream outputs during execution.
@@ -1506,7 +1506,7 @@ def __init__(
15061506
additional_authorized_imports: list[str] | None = None,
15071507
planning_interval: int | None = None,
15081508
executor: PythonExecutor = None,
1509-
executor_type: Literal["local", "e2b", "modal", "docker", "wasm"] = "local",
1509+
executor_type: Literal["local", "blaxel", "e2b", "modal", "docker", "wasm"] = "local",
15101510
executor_kwargs: dict[str, Any] | None = None,
15111511
max_print_outputs_length: int | None = None,
15121512
stream_outputs: bool = False,
@@ -1570,7 +1570,7 @@ def cleanup(self):
15701570
self.python_executor.cleanup()
15711571

15721572
def create_python_executor(self) -> PythonExecutor:
1573-
if self.executor_type not in {"local", "e2b", "modal", "docker", "wasm"}:
1573+
if self.executor_type not in {"local", "blaxel", "e2b", "modal", "docker", "wasm"}:
15741574
raise ValueError(f"Unsupported executor type: {self.executor_type}")
15751575

15761576
if self.executor_type == "local":
@@ -1582,6 +1582,7 @@ def create_python_executor(self) -> PythonExecutor:
15821582
if self.managed_agents:
15831583
raise Exception("Managed agents are not yet supported with remote code execution.")
15841584
remote_executors = {
1585+
"blaxel": BlaxelExecutor,
15851586
"e2b": E2BExecutor,
15861587
"docker": DockerExecutor,
15871588
"wasm": WasmExecutor,

0 commit comments

Comments
 (0)