Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
3307448
[model-gateway] wasm: add wasm module and module manager (#12471)
tonyluj Sep 21, 2025
65a39e2
[model-gateway] wasm: add wasm runtime and config (#12471)
tonyluj Sep 21, 2025
082e754
[model-gateway] wasm: runtime add thread pool (#12471)
tonyluj Sep 21, 2025
4f3cefb
[model-gateway] wasm: using wasm module manager as top level executor…
tonyluj Sep 21, 2025
890a999
[model-gateway] wasm: add basic metrics (#12471)
tonyluj Sep 21, 2025
92c6a76
[model-gateway] wasm: add runtime tests (#12471)
tonyluj Sep 29, 2025
66c9541
[model-gateway] wasm: add config unit tests (#12471)
tonyluj Sep 29, 2025
d4aef4f
[model-gateway] wasm: code format (#12471)
tonyluj Sep 29, 2025
0ffdde0
[model-gateway] wasm: drain all task when drop (#12471)
tonyluj Sep 29, 2025
2f838a6
[model-gateway] wasm: fix timeout when drop (#12471)
tonyluj Sep 29, 2025
1930935
[model-gateway] wasm: code format (#12471)
tonyluj Sep 29, 2025
808ce48
[model-gateway] wasm: add middleware attach type (#12471)
tonyluj Sep 30, 2025
3d59f00
[model-gateway] wasm: add errors (#12471)
tonyluj Sep 30, 2025
bd31f84
[model-gateway] wasm: code format (#12471)
tonyluj Sep 30, 2025
bc654fb
[model-gateway] wasm: add api to manage wasm modules (#12471)
tonyluj Sep 30, 2025
91f291e
[model-gateway] wasm: introduce wit interface (#12471)
tonyluj Oct 1, 2025
507224b
[model-gateway] wasm: add wit executor (#12471)
tonyluj Oct 1, 2025
cca52ee
[model-gateway] wasm: add middleware logic (#12471)
tonyluj Oct 1, 2025
99ae390
[model-gateway] wasm: fix conflicts (#12471)
tonyluj Oct 31, 2025
4e86de8
[model-gateway] wasm: remote unused executors (#12471)
tonyluj Oct 1, 2025
288bdbb
[model-gateway] wasm: add docs and examples (#12471)
tonyluj Oct 1, 2025
b31b7f3
[model-gateway] wasm: add myself to wasm CODEOWNERS (#12471)
tonyluj Oct 31, 2025
2c006c1
[model-gateway] wasm: code format (#12471)
tonyluj Oct 31, 2025
13f0bf1
[model-gateway] wasm: move functions to wasm module to make middlewar…
tonyluj Nov 4, 2025
e64d30b
[model-gateway] wasm: update examples for more safe access of RATE_LI…
tonyluj Nov 4, 2025
c6aa48e
[model-gateway] wasm: replace unwarp with error handling (#12471)
tonyluj Nov 4, 2025
95b5ae0
[model-gateway] wasm: remove unwrap in middleware (#12471)
tonyluj Nov 4, 2025
cbba663
[model-gateway] wasm: some minor improvements (#12471)
tonyluj Nov 4, 2025
b95479e
[model-gateway] wasm: simplify auth logic (#12471)
tonyluj Nov 4, 2025
2ba58ba
[model-gateway] wasm: remove unused code (#12471)
tonyluj Nov 4, 2025
543093b
[model-gateway] wasm: fix compile error for missing crates (#12471)
tonyluj Nov 20, 2025
42df7e8
[model-gateway] wasm: using workflow to add and remove wasm modules
tonyluj Nov 27, 2025
54a43bf
[model-gateway] wasm: add tests
tonyluj Nov 27, 2025
21668d5
[model-gateway] wasm: fix minor bugs for testing
tonyluj Nov 27, 2025
f48a124
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj Nov 28, 2025
c35d750
[model-gateway] wasm: fix cargo clippy warnings
tonyluj Nov 28, 2025
5dc89c7
[model-gateway] wasm: fix end of files
tonyluj Nov 28, 2025
93ccbfe
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj Nov 28, 2025
68d0159
[model-gateway] wasm: fix testing issue
tonyluj Nov 28, 2025
212a5f6
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj Nov 28, 2025
29fe306
[model-gateway] wasm: create wasm tests dynamically
tonyluj Nov 28, 2025
a0ce8cc
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj Dec 5, 2025
32b6900
[model-gateway] wasm: fix clippy warnings
tonyluj Dec 5, 2025
7776f46
[model-gateway] wasm: rename wit with interface
tonyluj Dec 5, 2025
e34ad98
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj Dec 5, 2025
dd9a0e1
[model-gateway] wasm: wit -> wasm interface type
tonyluj Dec 5, 2025
09acf3b
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj Dec 5, 2025
89171d0
Merge branch 'main' into tonyluj/sgl-router-wasm-latest
tonyluj Dec 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@
/sgl-router/src/routers @CatherineSue @key4ng @slin1237
/sgl-router/src/tokenizer @slin1237 @CatherineSue
/sgl-router/src/tool_parser @slin1237 @CatherineSue
/sgl-router/src/wasm @tonyluj
/sgl-router/examples/wasm @tonyluj
/test/srt/ascend @ping1jing2 @iforgetmyname
/test/srt/test_modelopt* @Edwardf0t1
7 changes: 7 additions & 0 deletions sgl-router/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ tokio-postgres = { version = "0.7.15", features = ["runtime","with-chrono-0_4","
deadpool-postgres = "0.14.1"


# wasm dependencies
sha2 = "0.10"
wasmtime = { version = "38.0", features = ["component-model", "async"] }
wasmtime-wasi = "38.0"
async-channel = "2.5"

[build-dependencies]
tonic-prost-build = "0.14.2"
prost-build = "0.14.1"
Expand All @@ -123,6 +129,7 @@ http-body-util = "0.1"
portpicker = "0.1"
tempfile = "3.8"
lazy_static = "1.4"
wasm-encoder = "0.242"
npyz = { version = "0.8", features = ["npz"] } # For reading numpy .npz files in golden tests

[[bench]]
Expand Down
27 changes: 27 additions & 0 deletions sgl-router/examples/wasm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Rust build artifacts
target/
**/target/

# Cargo lock files (examples don't need locked dependencies)
Cargo.lock
**/Cargo.lock

# Generated WASM files
*.wasm
*.component.wasm
**/*.wasm
**/*.component.wasm

# Build scripts output
build/

# IDE files
.idea/
.vscode/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db
102 changes: 102 additions & 0 deletions sgl-router/examples/wasm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# WASM Guest Examples for sgl-router

This directory contains example WASM middleware components demonstrating how to implement custom middleware for sgl-router using the WebAssembly Component Model.

## Examples Overview

### [wasm-guest-auth](./wasm-guest-auth/)

API key authentication middleware that validates API keys for requests to `/api` and `/v1` paths.

**Features:**
- Validates API keys from `Authorization` header or `x-api-key` header
- Returns `401 Unauthorized` for missing or invalid keys
- Attach point: `OnRequest` only

**Use case:** Protect API endpoints with API key authentication.

### [wasm-guest-logging](./wasm-guest-logging/)

Request tracking and status code conversion middleware.

**Features:**
- Adds tracking headers (`x-request-id`, `x-wasm-processed`, `x-processed-at`, `x-api-route`)
- Converts `500` errors to `503` for better client handling
- Attach points: `OnRequest` and `OnResponse`

**Use case:** Request tracing and error status code conversion.

### [wasm-guest-ratelimit](./wasm-guest-ratelimit/)

Rate limiting middleware with configurable limits.

**Features:**
- Rate limiting per identifier (API Key, IP, or Request ID)
- Default: 60 requests per minute
- Returns `429 Too Many Requests` when limit exceeded
- Attach point: `OnRequest` only

**Note:** This is a simplified demonstration with per-instance state. For production, use router-level rate limiting with shared state.

**Use case:** Protect against request flooding and abuse.

## Quick Start

Each example includes its own README with detailed build and deployment instructions. See individual example directories for:

- Build instructions
- Deployment configuration
- Customization options
- Testing examples

## Common Prerequisites

All examples require:

- Rust toolchain (latest stable)
- `wasm32-wasip2` target: `rustup target add wasm32-wasip2`
- `wasm-tools`: `cargo install wasm-tools`
- sgl-router running with WASM enabled (`--enable-wasm`)

## Building All Examples

```bash
cd examples/wasm
for example in wasm-guest-auth wasm-guest-logging wasm-guest-ratelimit; do
echo "Building $example..."
cd $example && ./build.sh && cd ..
done
```

## Deploying Multiple Modules

You can deploy all three modules together:

```bash
curl -X POST http://localhost:3000/wasm \
-H "Content-Type: application/json" \
-d '{
"modules": [
{
"name": "auth-middleware",
"file_path": "/path/to/wasm_guest_auth.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
},
{
"name": "logging-middleware",
"file_path": "/path/to/wasm_guest_logging.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}, {"Middleware": "OnResponse"}]
},
{
"name": "ratelimit-middleware",
"file_path": "/path/to/wasm_guest_ratelimit.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
}
]
}'
```

Modules execute in the order they are deployed. If a module returns `Reject`, subsequent modules won't execute.
10 changes: 10 additions & 0 deletions sgl-router/examples/wasm/wasm-guest-auth/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "wasm-guest-auth"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wit-bindgen = { version = "0.21", features = ["macros"] }
62 changes: 62 additions & 0 deletions sgl-router/examples/wasm/wasm-guest-auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# WASM Auth Example for sgl-router

This example demonstrates API key authentication middleware for sgl-router using the WebAssembly Component Model.

## Overview

This middleware validates API keys for requests to `/api` and `/v1` paths:

- Supports `Authorization: Bearer <key>` header
- Supports `Authorization: ApiKey <key>` header
- Supports `x-api-key` header
- Returns `401 Unauthorized` for missing or invalid keys

**Default API Key**: `secret-api-key-12345`

## Quick Start

### Build and Deploy

```bash
# Build
cd examples/wasm-guest-auth
./build.sh

# Deploy (replace file_path with actual path)
curl -X POST http://localhost:3000/wasm \
-H "Content-Type: application/json" \
-d '{
"modules": [{
"name": "auth-middleware",
"file_path": "/absolute/path/to/wasm_guest_auth.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
}]
}'
```

### Customization

Modify `EXPECTED_API_KEY` in `src/lib.rs`:

```rust
const EXPECTED_API_KEY: &str = "your-secret-key";
```

## Testing

```bash
# Test unauthorized (returns 401)
curl -v http://localhost:3000/api/test

# Test authorized (passes)
curl -v http://localhost:3000/api/test \
-H "Authorization: Bearer secret-api-key-12345"
```

## Troubleshooting

- Verify API key matches `EXPECTED_API_KEY` in code
- Check request header format and path (`/api` or `/v1`)
- Verify module is attached to `OnRequest` phase
- Check router logs for errors
77 changes: 77 additions & 0 deletions sgl-router/examples/wasm/wasm-guest-auth/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash
# Build script for WASM guest auth example
# This script simplifies the build process for the WASM middleware component

set -e

echo "Building WASM guest auth example..."

# Check if we're in the right directory
if [ ! -f "Cargo.toml" ]; then
echo "Error: Cargo.toml not found. Please run this script from the wasm-guest-auth directory."
exit 1
fi

# Check for required tools
command -v cargo >/dev/null 2>&1 || { echo "Error: cargo is required but not installed. Aborting." >&2; exit 1; }

# Check and install wasm32-wasip2 target
echo "Checking for wasm32-wasip2 target..."
if ! rustup target list --installed | grep -q "wasm32-wasip2"; then
echo "wasm32-wasip2 target not found. Installing..."
rustup target add wasm32-wasip2
echo "✓ wasm32-wasip2 target installed"
else
echo "✓ wasm32-wasip2 target already installed"
fi

# Check for wasm-tools
if ! command -v wasm-tools >/dev/null 2>&1; then
echo "Error: wasm-tools is required but not installed."
echo "Install it with: cargo install wasm-tools"
exit 1
fi

# Build with cargo (wit-bindgen uses cargo, not wasm-pack)
echo "Running cargo build..."
cargo build --target wasm32-wasip2 --release

# Output locations
WASM_MODULE="target/wasm32-wasip2/release/wasm_guest_auth.wasm"
WASM_COMPONENT="target/wasm32-wasip2/release/wasm_guest_auth.component.wasm"

if [ ! -f "$WASM_MODULE" ]; then
echo "Error: Build failed - WASM module not found"
exit 1
fi

# Check if the file is already a component
echo "Checking WASM file format..."
if wasm-tools print "$WASM_MODULE" 2>/dev/null | grep -q "^(\s*component"; then
echo "✓ WASM file is already in component format"
# Copy to component path for consistency
cp "$WASM_MODULE" "$WASM_COMPONENT"
else
# Wrap the WASM module into a component format
echo "Wrapping WASM module into component format..."
wasm-tools component new "$WASM_MODULE" -o "$WASM_COMPONENT"
if [ ! -f "$WASM_COMPONENT" ]; then
echo "Error: Failed to create component file"
exit 1
fi
fi

if [ -f "$WASM_COMPONENT" ]; then
echo ""
echo "✓ Build successful!"
echo " WASM module: $WASM_MODULE"
echo " WASM component: $WASM_COMPONENT"
echo ""
echo "Next steps:"
echo "1. Use the component file ($WASM_COMPONENT) when adding the module"
echo "2. Prepare the module configuration (see README.md for JSON format)"
echo "3. Use the API endpoint to add the module (see README.md for details)"
else
echo "Error: Component file not found"
exit 1
fi
70 changes: 70 additions & 0 deletions sgl-router/examples/wasm/wasm-guest-auth/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//! WASM Guest Auth Example for sgl-router
//!
//! This example demonstrates API key authentication middleware
//! for sgl-router using the WebAssembly Component Model.
//!
//! Features:
//! - API Key authentication

wit_bindgen::generate!({
path: "../../../src/wasm/interface",
world: "sgl-router",
});

use exports::sgl::router::{
middleware_on_request::Guest as OnRequestGuest,
middleware_on_response::Guest as OnResponseGuest,
};
use sgl::router::middleware_types::{Action, Request, Response};

/// Expected API Key (in production, this should be passed as configuration)
const EXPECTED_API_KEY: &str = "secret-api-key-12345";

/// Main middleware implementation
struct Middleware;

// Helper function to find header value
fn find_header_value(
headers: &[sgl::router::middleware_types::Header],
name: &str,
) -> Option<String> {
headers
.iter()
.find(|h| h.name.eq_ignore_ascii_case(name))
.map(|h| h.value.clone())
}

// Implement on-request interface
impl OnRequestGuest for Middleware {
fn on_request(req: Request) -> Action {
// API Key Authentication
// Check for API key in Authorization header for /api routes
if req.path.starts_with("/api") || req.path.starts_with("/v1") {
let api_key = find_header_value(&req.headers, "authorization")
.and_then(|h| {
h.strip_prefix("Bearer ")
.or_else(|| h.strip_prefix("ApiKey "))
.map(|s| s.to_string())
})
.or_else(|| find_header_value(&req.headers, "x-api-key"));

// Reject if API key is missing or invalid
if api_key.as_deref() != Some(EXPECTED_API_KEY) {
return Action::Reject(401);
}
}

// Authentication passed, continue processing
Action::Continue
}
}

// Implement on-response interface (empty - not used for auth)
impl OnResponseGuest for Middleware {
fn on_response(_resp: Response) -> Action {
Action::Continue
}
}

// Export the component
export!(Middleware);
10 changes: 10 additions & 0 deletions sgl-router/examples/wasm/wasm-guest-logging/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "wasm-guest-logging"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wit-bindgen = { version = "0.21", features = ["macros"] }
Loading
Loading