WASM Plugins¶
WebAssembly (WASM) plugins enable custom middleware logic in SMG's request pipeline without recompiling or restarting the gateway.
Overview¶
Dynamic Extension¶
Deploy custom logic at runtime via REST API. Add or remove plugins without restarting the gateway; to update one, remove it and add the new build.
Sandboxed Execution¶
Plugins run in isolated WASM environments with strict resource limits. No access to host memory, filesystem, or network.
Language Agnostic¶
Write plugins in Rust, Go, C, or any language that compiles to WebAssembly Component Model.
High Performance¶
Compiled components are cached per runtime thread, so only a component's first run on each thread pays for compilation.
How It Works¶
WASM plugins execute in SMG's middleware layer, intercepting requests before they reach workers and responses before they return to clients.
The middleware runs on the inference routes: /v1/chat/completions, /v1/completions, /generate, /v1/responses and /v1/conversations (with their sub-paths), /v1/messages and /v1/messages/count_tokens, /v1/embeddings, /v1/rerank and /rerank, /v1/classify, /v1/interactions, /v1/tokenize, /v1/detokenize, and the Realtime REST endpoints. It does not run on /v1/audio/transcriptions, the Realtime WebSocket and WebRTC routes, or the public, admin, and worker-management routes.
Plugin Chain Execution¶
SMG runs every plugin attached at a point, in no defined order: don't rely on deployment order. Each plugin receives the request/response and returns an action:
- Continue: Pass through to the next plugin (or worker)
- Reject(status): Stop processing and return an error response immediately
- Modify(changes): Apply transformations and continue
If any plugin returns Reject, subsequent plugins are skipped and the error response is returned to the client: on a request, the status with an empty body; on a response, the status with the response body so far. A plugin that fails or runs past its time limit is skipped, and processing continues with the next one.
Attach Points¶
Plugins register at specific points in the request lifecycle:
| Attach Point | When | Use Cases |
|---|---|---|
| OnRequest | Before forwarding to worker | Authentication, rate limiting, validation, header injection |
| OnResponse | After receiving worker response | Response transformation, error normalization, logging |
Example Plugins¶
SMG includes ready-to-use example plugins demonstrating common middleware patterns:
auth-middleware¶
API key authentication for /api and /v1 routes.
- Validates
Authorizationorx-api-keyheader - Returns 401 Unauthorized on failure
- Attach point: OnRequest
ratelimit-middleware¶
Per-identifier rate limiting with configurable thresholds.
- 60 requests/minute default
- Tracks by API key, IP, or request ID
- Returns 429 Too Many Requests when exceeded
- Attach point: OnRequest
- SMG runs each invocation in a fresh component instance, so the example's in-memory counters don't carry over between requests; treat it as a template
logging-middleware¶
Request tracking and response transformation.
- Adds
x-request-id,x-wasm-processed,x-processed-at, andx-api-route(on/apiand/v1paths) - Converts 500 → 503 for better client handling
- Attach points: OnRequest and OnResponse
Find complete source code and build instructions in examples/wasm/.
Plugin Development¶
Interface¶
Plugins implement the SMG middleware interface using the WebAssembly Component Model:
// OnRequest: Called before forwarding to worker
fn on_request(req: Request) -> Action {
// Validate, modify, or reject the request
Action::Continue
}
// OnResponse: Called after receiving worker response
fn on_response(resp: Response) -> Action {
// Transform or log the response
Action::Continue
}Actions¶
| Action | Effect | Example |
|---|---|---|
Action::Continue |
Pass through unmodified | Logging, metrics |
Action::Reject(401) |
Return error immediately | Auth failure |
Action::Modify(changes) |
Apply transformations | Add headers, rewrite body |
Request Context¶
Plugins receive rich context for decision-making:
| Field | Description |
|---|---|
method |
HTTP method (GET, POST, etc.) |
path |
Request path |
query |
URL query string |
headers |
All request headers |
body |
Request body (if present) |
request_id |
Unique request identifier |
now_epoch_ms |
Current timestamp |
Configuration¶
Enabling WASM Support¶
smg --enable-wasm --worker-urls http://worker:8000Runtime Settings¶
| Setting | Value | Description |
|---|---|---|
max_memory_pages |
1024 | Maximum memory (64KB per page = 64MB) |
max_execution_time_ms |
1000 | Execution timeout per invocation |
max_stack_size |
1 MB | Stack size per invocation |
module_cache_size |
10 | Compiled components cached per runtime thread |
max_body_size |
10 MB | Largest request or response body a plugin can receive |
These values are fixed in v1.11.0; no flag changes them. Plugins run on a pool of runtime threads, one per CPU core up to 4.
With an OnRequest plugin attached, SMG reads the whole request body before running it, and answers 400 when the body exceeds max_body_size. With an OnResponse plugin attached, it reads each non-streaming response body the same way, and answers 500 when the body is too large.
Module Management¶
Plugins are managed via the Admin API at runtime. These routes need --enable-wasm (without it they answer 500) and are protected like the other admin routes.
Deploy Plugins¶
curl -X POST http://localhost:30000/wasm \
-H "Content-Type: application/json" \
-d '{
"modules": [
{
"name": "auth-middleware",
"file_path": "/plugins/auth.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
},
{
"name": "logging-middleware",
"file_path": "/plugins/logging.component.wasm",
"module_type": "Middleware",
"attach_points": [
{"Middleware": "OnRequest"},
{"Middleware": "OnResponse"}
]
}
]
}'SMG loads each module before it answers. The response lists every module with an add_result: {"Success": "<module uuid>"}, or {"Error": "<message>"} for a module that failed, in which case the status is 400.
List Plugins¶
curl http://localhost:30000/wasmRemove Plugin¶
curl -X DELETE http://localhost:30000/wasm/{uuid}Security Model¶
WASM plugins execute in a sandboxed environment with multiple protection layers:
| Layer | Protection |
|---|---|
| Path Validation | Only absolute paths without . or .. segments, .wasm extension required, system directories blocked (checked again after resolving symlinks) |
| Runtime Sandboxing | No access to host memory, filesystem, network, or system calls |
| Resource Limits | Memory caps, execution timeouts, stack size limits |
| Deduplication | A module whose SHA-256 hash matches a loaded module is rejected |
Blocked directories: /etc/, /proc/, /sys/, /dev/, /boot/, /root/, /var/log/, /var/run/
Performance¶
The first run of a component on each runtime thread compiles it, and later runs on that thread reuse the compiled component. Every invocation still instantiates the component fresh. GET /wasm reports execution counts (total, successful, failed) and the total, average, and maximum execution time, so you can measure your plugins' overhead.