PolyAgent's Rust Agent Core provides a secure WebAssembly System Interface (WASI) sandbox for code execution. This sandbox offers:
- Security Isolation: Memory-safe execution with resource limits
- Deterministic Execution: Consistent behavior across platforms
- Resource Control: Configurable memory, CPU, and timeout limits
- Filesystem Safety: Read-only access with whitelisted paths
- Network Isolation: No network access at WASI capability level
- Prerequisites
- Platform-Specific Setup
- Basic Usage
- Advanced Usage
- Integration Guide
- Configuration
- Troubleshooting
- Security Considerations
- Examples
- Rust 1.70+ with cargo
- Docker & Docker Compose (for full platform)
- WebAssembly toolchain (platform-specific, see below)
- Python interpreter
- JavaScript runtime
- Shell/bash commands
- Native binaries
To execute Python or other languages, you need to compile them to WebAssembly first (e.g., using Pyodide for Python).
# Option 1: Install wabt (WebAssembly Binary Toolkit)
brew install wabt
# Verify installation
wat2wasm --version
# Option 2: Install wasm-tools (Rust-based)
cargo install wasm-tools
# Option 3: Install wasmtime CLI (includes additional tools)
brew install wasmtime# Ubuntu/Debian
sudo apt-get update
sudo apt-get install wabt
# Fedora/RHEL
sudo dnf install wabt
# Arch Linux
sudo pacman -S wabt
# Alternative: Install from GitHub releases
wget https://github.com/WebAssembly/wabt/releases/download/1.0.34/wabt-1.0.34-linux.tar.gz
tar xzf wabt-1.0.34-linux.tar.gz
export PATH=$PATH:$(pwd)/wabt-1.0.34/bin# Option 1: Using Chocolatey
choco install wabt
# Option 2: Using Scoop
scoop install wabt
# Option 3: Download from GitHub
# Visit: https://github.com/WebAssembly/wabt/releases
# Download wabt-1.0.34-windows.zip and extract to PATH# Compile the example hello-wasi.wat file
wat2wasm docs/assets/hello-wasi.wat -o /tmp/hello-wasi.wasm
# Verify the generated WASM file
file /tmp/hello-wasi.wasm
# Output: /tmp/hello-wasi.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)cd rust/agent-core
# Run the WASI hello example
cargo run --example wasi_hello -- /tmp/hello-wasi.wasm
# Expected output:
# Hello from WASI!cd rust/agent-core
# Run the base64 payload test
RUST_LOG=info cargo test test_code_executor_with_base64_payload -- --nocapture
# Run all WASI-related tests
cargo test wasi -- --nocapturePolyAgent supports executing Python code in the WASI sandbox through two approaches:
- Python Interpreter WASM: Using a full Python interpreter compiled to WebAssembly
- Python-to-WASM Transpilation: Converting simple Python code directly to WASM
- Size: ~20MB
- Version: Python 3.11.4
- Compatibility: Full CPython standard library
- Best for: Standard Python scripts
# Download Python WASI interpreter
mkdir -p /tmp/python-wasi
cd /tmp/python-wasi
curl -LO https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/python%2F3.11.4%2B20230714-11be424/python-3.11.4.wasm
# Verify download
ls -lh python-3.11.4.wasm
# Should show ~20MB file- Size: 20MB+ (core + packages)
- Features: NumPy, Pandas, SciPy support
- Best for: Data science workloads
# Download Pyodide (browser-focused, needs adaptation)
curl -LO https://github.com/pyodide/pyodide/releases/latest/download/pyodide-core.tar.bz2
tar -xjf pyodide-core.tar.bz2- Size: 5-10MB
- Compatibility: ~95% CPython compatible
- Best for: Lightweight scripts, Rust ecosystem
# Download RustPython WASM
curl -LO https://github.com/RustPython/RustPython/releases/latest/download/rustpython.wasmThe python_wasi_runner tool in the LLM service bridges Python code execution to the Rust WASI sandbox:
# In PolyAgent's workflow, the tool expects:
{
"tool": "python_wasi_runner",
"parameters": {
"code": "print('Hello from Python')",
"interpreter_wasm_path": "/tmp/python.wasm", # OR
"interpreter_wasm_base64": "<base64-encoded-wasm>",
"stdin": "", # Optional input
"argv": [] # Optional arguments
}
}For direct WASI execution, use the Rust code_executor tool:
# The code_executor expects:
{
"tool": "code_executor",
"parameters": {
"wasm_base64": "<base64-encoded-wasm>", # OR
"wasm_path": "/path/to/module.wasm",
"stdin": "input data"
}
}- Copy Python WASM to container:
# Download locally first
curl -LO https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/python%2F3.11.4%2B20230714-11be424/python-3.11.4.wasm
# Copy to LLM service container
docker cp python-3.11.4.wasm polyagent-llm-service-1:/opt/python.wasm
# Copy to Agent Core container (if needed)
docker cp python-3.11.4.wasm polyagent-agent-core-1:/opt/python.wasm- Set environment variable in docker-compose.yml:
services:
llm-service:
environment:
- PYTHON_WASI_WASM_PATH=/opt/python.wasm
agent-core:
volumes:
- ./wasm-interpreters:/opt/wasm-interpreters:ro- Or mount as volume:
services:
llm-service:
volumes:
- /tmp/python-wasi/python-3.11.4.wasm:/opt/python.wasm:ro# Set environment variable
export PYTHON_WASI_WASM_PATH=/tmp/python-wasi/python-3.11.4.wasm
# Or configure in .env file
echo "PYTHON_WASI_WASM_PATH=/tmp/python-wasi/python-3.11.4.wasm" >> .env# Submit via API
./scripts/submit_task.sh 'Use python_wasi_runner to execute: print("Hello PolyAgent")'# Create test script
cat > /tmp/test.py << 'EOF'
import math
result = math.factorial(10)
print(f"10! = {result}")
EOF
# Execute via PolyAgent
./scripts/submit_task.sh 'Execute the Python code that calculates factorial of 10'# Test Python WASM directly with our WASI sandbox
cd rust/agent-core
echo 'print("Test")' | cargo run --example wasi_hello -- /tmp/python-wasi/python-3.11.4.wasm -- -c 'import sys; exec(sys.stdin.read())'-
Python.wasm Limitations:
- No pip/package installation at runtime
- Limited to pre-compiled standard library
- No native extensions (C modules)
- No network access (WASI security)
- No filesystem write access (configurable)
-
Performance Considerations:
- ~20MB interpreter must be loaded for each execution
- Startup overhead: ~100-500ms
- Memory usage: 256MB limit (configurable)
-
Integration Status:
python_wasi_runnertool exists but needs proper argv handling- Full Python interpreter invocation is complex
- Simple expressions work best
- Interpreter Caching: Cache loaded interpreter in memory
- Package Support: Pre-bundle common packages
- Streaming Output: Support real-time output streaming
- Debugging: Add Python debugger support
For simple Python expressions, consider transpiling directly to WASM:
# Simple Python code
print("Hello")
print(2 + 2)
# Transpiles to WAT:
(module
(import "wasi_snapshot_preview1" "fd_write" ...)
(memory 1)
(data (i32.const 100) "Hello\n")
(data (i32.const 110) "4\n")
(func $main (export "_start")
;; Print "Hello"
;; Print "4"
)
)This approach is faster but limited to basic operations.
# Encode WASM file as base64
BASE64_WASM=$(base64 -b 0 /tmp/hello-wasi.wasm) # macOS
# OR
BASE64_WASM=$(base64 -w 0 /tmp/hello-wasi.wasm) # Linux
# Use in tool execution (example)
echo "Base64 WASM: ${BASE64_WASM:0:50}..." # Show first 50 charsCreate custom.wat:
(module
(import "wasi_snapshot_preview1" "fd_write"
(func $fd_write (param i32 i32 i32 i32) (result i32)))
(memory 1)
(export "memory" (memory 0))
(data (i32.const 8) "Custom WASI Module\n")
(func $main (export "_start")
;; Create iovec structure
(i32.store (i32.const 0) (i32.const 8)) ;; buf pointer
(i32.store (i32.const 4) (i32.const 19)) ;; buf length
;; Write to stdout (fd=1)
(call $fd_write
(i32.const 1) ;; stdout
(i32.const 0) ;; iovs pointer
(i32.const 1) ;; iovs_len
(i32.const 20) ;; nwritten pointer
)
drop
)
)Compile and run:
wat2wasm custom.wat -o custom.wasm
cargo run --example wasi_hello -- custom.wasmCreate rust-wasm/Cargo.toml:
[package]
name = "wasi-example"
version = "0.1.0"
edition = "2021"
[dependencies]
[lib]
crate-type = ["cdylib"]Create rust-wasm/src/main.rs:
fn main() {
println!("Hello from Rust WASI!");
}Build and run:
cd rust-wasm
cargo build --target wasm32-wasi --release
cd ../rust/agent-core
cargo run --example wasi_hello -- ../../rust-wasm/target/wasm32-wasi/release/wasi_example.wasmThe WASI sandbox integrates with PolyAgent's tool system:
// Tool execution request
message ToolCallRequest {
string tool_name = 1; // Use "code_executor"
google.protobuf.Struct parameters = 2;
}
// Parameters for code_executor:
// - wasm_base64: Base64-encoded WASM module (preferred)
// - wasm_path: Path to WASM file (alternative)
// - stdin: Optional input data# Using grpcurl (requires agent-core running on port 50051)
grpcurl -plaintext -d '{
"tool_name": "code_executor",
"parameters": {
"wasm_base64": "'$(base64 -b 0 /tmp/hello-wasi.wasm)'",
"stdin": ""
}
}' localhost:50051 polyagent.agent.AgentService/ExecuteToolThe orchestrator can route code execution tasks to the WASI sandbox:
// In Go orchestrator
result, err := agentClient.ExecuteTool(ctx, &pb.ToolCallRequest{
ToolName: "code_executor",
Parameters: map[string]interface{}{
"wasm_base64": base64WasmModule,
"stdin": inputData,
},
})Edit config/polyagent.yaml:
wasi:
# Memory limit in bytes (default: 256MB)
memory_limit_bytes: 268435456
# CPU fuel limit (computational steps)
max_fuel: 100000000
# Execution timeout in milliseconds
execution_timeout_ms: 30000
# Allowed filesystem paths (read-only)
allowed_paths:
- "/tmp"
- "/data/readonly"
# Environment variables (if needed)
env_vars:
HOME: "/tmp"
PATH: "/usr/bin"wasi:
# Sandbox security options
security:
# Disable network capabilities
allow_network: false
# File system access mode
fs_readonly: true
# Process spawning
allow_subprocess: false
# Clock access
allow_clock: true
# Random number generation
allow_random: trueSolution: Install WebAssembly tools
# macOS
brew install wabt
# Linux
sudo apt-get install wabtIssue: Default size limit is 50MB
Solution: Split your module or optimize size
# Check WASM size
ls -lh your-module.wasm
# Optimize with wasm-opt
wasm-opt -Os input.wasm -o output.wasmIssue: Module exceeded 30-second timeout
Solution: Increase timeout in config or optimize code
wasi:
execution_timeout_ms: 60000 # 60 secondsIssue: Module requested more than 256MB memory
Solution: Increase limit or reduce memory usage
wasi:
memory_limit_bytes: 536870912 # 512MBEnable detailed logging:
# Set Rust log level
export RUST_LOG=polyagent_agent_core=debug,wasi_sandbox=trace
# Run with verbose output
cargo run --example wasi_hello -- /tmp/test.wasm✅ Enforced:
- Memory isolation (separate linear memory)
- CPU limits (fuel mechanism)
- No network access (capability not granted)
- Read-only filesystem (configurable paths)
- No process spawning
- Resource limits (memory, time, fuel)
- Side-channel timing attacks
- Speculative execution vulnerabilities
- Resource exhaustion via legitimate operations
- Validate Input: Always validate WASM modules before execution
- Set Limits: Configure appropriate resource limits
- Audit Modules: Review WASM source before deployment
- Monitor Usage: Track resource consumption metrics
- Update Dependencies: Keep Wasmtime runtime updated
Located at: docs/assets/hello-wasi.wat
# Compile and run
wat2wasm docs/assets/hello-wasi.wat -o /tmp/hello.wasm
cd rust/agent-core
cargo run --example wasi_hello -- /tmp/hello.wasmCreate input-reader.wat:
(module
(import "wasi_snapshot_preview1" "fd_read"
(func $fd_read (param i32 i32 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_write"
(func $fd_write (param i32 i32 i32 i32) (result i32)))
(memory 1)
(export "memory" (memory 0))
(func $main (export "_start")
;; Read from stdin and echo to stdout
;; Implementation details...
)
)cd rust/agent-core
# Run the existing test
cargo test test_code_executor_with_base64_payload -- --nocapture
# View test implementation
cat src/tools.rs | grep -A 50 "test_code_executor_with_base64_payload"Typical execution times on modern hardware:
| Operation | Time | Memory |
|---|---|---|
| WASM load & validate | ~1ms | 1MB |
| Simple hello world | ~5ms | 4MB |
| Complex computation (factorial 1000) | ~50ms | 8MB |
| Memory-intensive (array sorting) | ~200ms | 64MB |
-
Language Support:
- Python via Pyodide
- JavaScript via QuickJS
- Ruby via ruby.wasm
-
Capabilities:
- Controlled network access
- Persistent storage
- Inter-module communication
-
Developer Tools:
- WASM debugger integration
- Performance profiler
- Module marketplace
For questions or issues, please refer to the main PolyAgent documentation or open an issue in the repository.