Sandbox API¶
sandbox ¶
orqest.sandbox — safe execution of dynamic tool implementations.
The Protocol is small and explicit: validate then execute.
Three backends ship today:
- :class:
InProcessSandbox— Tier 0; in-processexec()with AST-level static restriction and a curated__builtins__set. Requires explicitunsafe=Trueat construction because there is no real isolation. Suitable for tests and tightly-controlled dev workflows. NOT for LLM-generated code from untrusted sources. - :class:
SubprocessSandbox— Tier 1, the production default. Subprocess isolation withRLIMIT_AS+RLIMIT_CPU(POSIX) + outerasyncio.wait_fortimeout. The wrapper subprocess runs against the same curated__builtins__(from :mod:orqest.sandbox._safe_builtins) so reflection helpers and the unsafe builtins are never reachable. JSON args/result; stdin/stdout transport. - :class:
orqest.sandbox.docker.DockerSandbox— Tier 2; per-session container running the publishedorqest/agent-runtimeimage. Requiresuv sync --group docker. Imported lazily from theorqest.sandbox.dockersubmodule so the host-sidedockerSDK stays an optional dep. Adds scope-separated JWT auth (agentfor execution,operatorforpromote_tool/forget_tool) and per-user persisted tool library.
Every tier rejects the same set of static escapes (default-deny imports,
reflection helpers, dunder reach-through, string-keyed subscript access —
see :mod:orqest.sandbox._static) and runs with the same curated
__builtins__ (:mod:orqest.sandbox._safe_builtins). Identifier paths
that feed into per-agent workspaces are bounded by
:mod:orqest.sandbox._identifiers.
Third parties can ship :class:E2BSandbox / :class:WasmSandbox /
:class:FirecrackerSandbox against the same :class:Sandbox Protocol —
no changes required in core.
The matching consumer is :class:orqest.autonomy.tool_factory.DynamicToolFactory,
which turns a :class:GeneratedToolSpec (carrying an implementation string)
into a runnable pydantic_ai.Tool via this Protocol.
SandboxRunError ¶
SandboxRunError(
message: str,
*,
stage: str,
code_snippet: str,
underlying: ExecutionResult
| ValidationError
| None = None,
)
Raised by :func:run_in_sandbox on validation / execution failure.
Attributes:
| Name | Type | Description |
|---|---|---|
stage |
|
|
code_snippet |
First ~200 chars of the offending implementation, for diagnostics. |
|
underlying |
The raw :class: |
Source code in orqest/sandbox/helpers.py
InProcessSandbox ¶
Tier-0 sandbox — see module docstring. Refuses unsafe=False.
Source code in orqest/sandbox/inprocess.py
validate
async
¶
Static AST check; raise :class:ValidationError on issues.
Source code in orqest/sandbox/inprocess.py
execute
async
¶
execute(
code: str,
*,
args: dict[str, Any],
allowed_imports: set[str],
timeout_s: float = 5.0,
memory_mb: int = 128,
agent_id: str | None = None,
dependencies: list[str] | None = None,
) -> ExecutionResult
Validate, then run the code in a restricted namespace.
Note that timeout_s, memory_mb, agent_id, and
dependencies are accepted for Protocol conformance but
not enforced by this backend — the in-process path has no
process boundary to enforce them on, and there are no per-agent
venvs in-process.
Source code in orqest/sandbox/inprocess.py
ExecutionResult ¶
Outcome of one :meth:Sandbox.execute call.
Always emitted regardless of success — :class:Sandbox implementations
MUST NOT raise for user-code failures (those land in :attr:error).
Reserved for infrastructure failures (e.g., subprocess crash before
handshake completes) which still raise from :meth:Sandbox.execute.
success
instance-attribute
¶
True when the implementation ran to completion and returned a
value without raising. False for any user-code exception, timeout,
memory cap, or non-JSON-serializable return.
output
class-attribute
instance-attribute
¶
JSON-serializable value the implementation returned. None on
failure or when the implementation explicitly returned None.
error
class-attribute
instance-attribute
¶
Captured exception message (or timeout / memory-cap signal) when
:attr:success is False. None on success.
stdout
class-attribute
instance-attribute
¶
Captured stdout from the implementation. Useful for debugging
LLM-generated code that prints intermediate values.
duration_ms
class-attribute
instance-attribute
¶
Wall-clock time spent inside the sandbox boundary.
Sandbox ¶
Protocol for safe execution of dynamic tool implementations.
Two-stage contract — see module docstring. Implementations are async so they can do off-thread / off-process work (subprocess calls, HTTP to a sandbox provider, etc.) without blocking the agent loop.
validate
async
¶
execute
async
¶
execute(
code: str,
*,
args: dict[str, Any],
allowed_imports: set[str],
timeout_s: float = 5.0,
memory_mb: int = 128,
agent_id: str | None = None,
dependencies: list[str] | None = None,
) -> ExecutionResult
Run the (pre-validated) code with args and return the result.
Always returns :class:ExecutionResult; success=False captures
user-code failures, timeouts, memory caps, or unserializable output.
Infrastructure failures (subprocess crash before handshake) still
raise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
str
|
The implementation source. |
required |
args
|
dict[str, Any]
|
Per-call arguments passed to the implementation as |
required |
allowed_imports
|
set[str]
|
Static-validation allowlist of top-level modules
permitted in |
required |
timeout_s
|
float
|
Wall-clock cap inside the sandbox. |
5.0
|
memory_mb
|
int
|
Memory cap (enforced by Tier-1+; Tier-0 ignores). |
128
|
agent_id
|
str | None
|
Optional agent identifier — Tier-2 (Docker) routes
execution into the agent's per-agent subfolder + |
None
|
dependencies
|
list[str] | None
|
Optional list of pip specifiers (e.g.
|
None
|
Source code in orqest/sandbox/protocol.py
__aenter__
async
¶
ValidationError ¶
Raised by :meth:Sandbox.validate when static checks fail.
Examples: a disallowed import, a syntax error, an explicit eval
call, or dunder attribute access (obj.__class__).
Source code in orqest/sandbox/protocol.py
SubprocessSandbox ¶
Tier-1 sandbox — subprocess with resource limits + outer timeout.
See module docstring for what this DOES protect against (memory, CPU, timeout, in-process namespace bleed) and what it does NOT (network, filesystem reads, child subprocesses if CPU cap permits).
execute
async
¶
execute(
code: str,
*,
args: dict[str, Any],
allowed_imports: set[str],
timeout_s: float = 5.0,
memory_mb: int = 128,
agent_id: str | None = None,
dependencies: list[str] | None = None,
) -> ExecutionResult
Run code in a fresh subprocess. agent_id and dependencies
are accepted for Protocol conformance but ignored — Tier-1 has no
per-agent venv concept (use Tier-2 :class:DockerSandbox for that).
Source code in orqest/sandbox/subprocess.py
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | |
run_in_sandbox
async
¶
run_in_sandbox(
code: str,
*,
return_expression: str | None = None,
args: dict[str, Any] | None = None,
allowed_imports: set[str] | None = None,
sandbox: Sandbox | None = None,
timeout_s: float = 5.0,
memory_mb: int = 128,
) -> Any
Run code in a sandbox; return the value (or raise :class:SandboxRunError).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
str
|
Python source — typically a function definition. The body runs
inside an isolated |
required |
return_expression
|
str | None
|
When given, appended as |
None
|
args
|
dict[str, Any] | None
|
Dict passed as |
None
|
allowed_imports
|
set[str] | None
|
Top-level module names the candidate may import.
Default empty (any |
None
|
sandbox
|
Sandbox | None
|
An optional :class: |
None
|
timeout_s
|
float
|
Wall-clock cap on execution. Default 5.0s. |
5.0
|
memory_mb
|
int
|
Memory cap in MB. Default 128. |
128
|
Returns:
| Type | Description |
|---|---|
Any
|
Whatever the wrapped function returns (JSON-serialisable values only, |
Any
|
per the sandbox Protocol). |
Raises:
| Type | Description |
|---|---|
SandboxRunError
|
Validation failure ( |
Source code in orqest/sandbox/helpers.py
run_in_sandbox_safe
async
¶
run_in_sandbox_safe(
code: str,
*,
return_expression: str | None = None,
args: dict[str, Any] | None = None,
allowed_imports: set[str] | None = None,
sandbox: Sandbox | None = None,
timeout_s: float = 5.0,
memory_mb: int = 128,
) -> tuple[bool, Any, str | None]
Non-raising variant of :func:run_in_sandbox.
Returns (success, output, error_message). On success: (True, result, None).
On any failure (validation or execution): (False, None, <error_msg>).
Suited for code that wants to handle failure inline without try/except — e.g., test-driven loops that iterate over many candidates and need a per-candidate verdict without exception bookkeeping.