Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
50 changes: 34 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -335,28 +335,30 @@ samples:
echo -e "$(RED)❌ No suitable compiler found (zig, or clang+WASI_SYSROOT). Install zig or set WASI_SYSROOT$(NC)"; exit 1; \
fi; \
fi
@if [ "$(BUILD_RUST_SAMPLES)" = "1" ]; then \
@if [ "$(BUILD_JS_SAMPLES)" = "1" ]; then \
if command -v cargo >/dev/null 2>&1; then \
echo -e "$(BLUE)🦀 Building Rust WASM samples... / 构建Rust WASM示例...$(NC)"; \
mkdir -p "$(SAMPLES_RUST_BUILD)"; \
for name in $(RUST_SAMPLES); do \
dir="$(REPO_ROOT)/$(SAMPLES_RUST_DIR)/$$name"; \
echo -e "$(BLUE)🟨 Building WASM-JS samples... / 构建WASM-JS示例...$(NC)"; \
mkdir -p "$(SAMPLES_JS_BUILD)" "$(SAMPLES_RUST_BUILD)"; \
for name in $(JS_SAMPLES); do \
dir="$(REPO_ROOT)/$(SAMPLES_JS_DIR)/$$name"; \
if [ ! -f "$$dir/Cargo.toml" ]; then \
echo -e "$(YELLOW)⚠️ Rust sample missing Cargo.toml: $$dir (skip) / 缺少Cargo.toml,跳过$(NC)"; \
echo -e "$(YELLOW)⚠️ Sample missing Cargo.toml: $$dir (skip) / 缺少Cargo.toml,跳过$(NC)"; \
continue; \
fi; \
( cd "$$dir" && cargo build --release --target wasm32-wasip1 ) || (echo -e "$(RED)❌ rust wasm build failed: $$name (need rustup target wasm32-wasip1) / Rust wasm构建失败(需要安装wasm32-wasip1目标)$(NC)"; exit 1); \
( cd "$$dir" && cargo build --release --target wasm32-wasip1 ) || (echo -e "$(RED)❌ wasm-js build failed: $$name (need rustup target wasm32-wasip1) / WASM-JS构建失败(需要安装wasm32-wasip1目标)$(NC)"; exit 1); \
in="$$dir/target/wasm32-wasip1/release/$$name.wasm"; \
out="$(SAMPLES_RUST_BUILD)/$$name.wasm"; \
out_js="$(SAMPLES_JS_BUILD)/$$name.wasm"; \
out_rust="$(SAMPLES_RUST_BUILD)/$$name.wasm"; \
if [ -f "$$in" ]; then \
cp "$$in" "$$out"; \
echo -e "$(GREEN)✅ Built Rust sample: $$out$(NC)"; \
cp "$$in" "$$out_js"; \
cp "$$in" "$$out_rust"; \
echo -e "$(GREEN)✅ Built WASM-JS sample: $$out_js$(NC)"; \
else \
echo -e "$(RED)❌ Rust output missing: $$in$(NC)"; exit 1; \
echo -e "$(RED)❌ WASM-JS output missing: $$in$(NC)"; exit 1; \
fi; \
done; \
else \
echo -e "$(YELLOW)⚠️ cargo not found, skipping Rust WASM samples / 未找到cargo,跳过Rust WASM示例$(NC)"; \
echo -e "$(YELLOW)⚠️ cargo not found, skipping WASM-JS samples / 未找到cargo,跳过WASM-JS示例$(NC)"; \
fi; \
fi
@echo -e "$(GREEN)✅ Samples build completed / 示例构建完成$(NC)"
Expand Down Expand Up @@ -435,7 +437,23 @@ e2e-linux:
SAMPLES_DIR := samples/wasm-c
SAMPLES_BUILD := samples/build
SAMPLES_CFLAGS ?=
SAMPLES_RUST_DIR := samples/wasm-rust
SAMPLES_RUST_BUILD := $(SAMPLES_BUILD)/rust
RUST_SAMPLES ?= chat_completion chat_completion_tool_sum
BUILD_RUST_SAMPLES ?= 1
SAMPLES_JS_DIR ?= samples/wasm-js
SAMPLES_JS_BUILD ?= $(SAMPLES_BUILD)/js
JS_SAMPLES ?= chat_completion chat_completion_tool_sum
BUILD_JS_SAMPLES ?= 1
SAMPLES_RUST_DIR ?= $(SAMPLES_JS_DIR)
SAMPLES_RUST_BUILD ?= $(SAMPLES_BUILD)/rust
RUST_SAMPLES ?= $(JS_SAMPLES)
BUILD_RUST_SAMPLES ?= $(BUILD_JS_SAMPLES)

ifeq ($(origin JS_SAMPLES), file)
ifeq ($(origin RUST_SAMPLES), command line)
JS_SAMPLES := $(RUST_SAMPLES)
endif
endif

ifeq ($(origin BUILD_JS_SAMPLES), file)
ifeq ($(origin BUILD_RUST_SAMPLES), command line)
BUILD_JS_SAMPLES := $(BUILD_RUST_SAMPLES)
endif
endif
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Docs:
make samples
```

Artifacts are written to `samples/build/` (C) and `samples/build/rust/` (Rust).
Artifacts are written to `samples/build/` (C) and `samples/build/js/` (WASM-JS, compat: `samples/build/rust/`).

Docs:

Expand Down
2 changes: 1 addition & 1 deletion README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Web Admin 提供 Nodes/Tasks/Files/Backends 等页面。
make samples
```

产物输出到 `samples/build/`(C)与 `samples/build/rust/`(Rust)。
产物输出到 `samples/build/`(C)与 `samples/build/js/`(WASM-JS;兼容:`samples/build/rust/`)。

文档:

Expand Down
8 changes: 4 additions & 4 deletions docs/rust-sdk-boa-wasm-design-en.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Add `sdk/rust/` and organize it as multiple crates (workspace style) to keep con
- map `spear-wasm` to JS-friendly APIs (Promise, options objects)
- maintain tool handler registry (JS tool handler table)

4) Samples (`samples/wasm-rust/*`) (WASI executables)
4) Samples (`samples/wasm-js/*`) (JS-first; built as WASI executables via a Boa JS runner)
- A small runner binary that:
- loads user JS (embedded or via WASI allowed dirs)
- creates Boa `Context`
Expand Down Expand Up @@ -344,18 +344,18 @@ To better match JS ecosystem expectations, consider adding these hostcalls later
- extend existing approach (see `tests/wasm_openai_e2e_tests.rs`) with “Boa runtime + chat completion” e2e
- Samples:
- WASM-C: `samples/wasm-c/*`
- WASM-Rust (Boa runner): `samples/wasm-rust/chat_completion`, `samples/wasm-rust/chat_completion_tool_sum`
- WASM-JS (Boa JS runner): `samples/wasm-js/chat_completion`, `samples/wasm-js/chat_completion_tool_sum`

## 9. Milestones

M1 (minimum viable)
- `spear-wasm-sys` + `spear-wasm` wrappers for existing hostcalls
- A Rust WASI runner sample (`samples/wasm-rust/chat_completion`) runs a single JS file and exposes `Spear.chat.completions.create`
- A WASM-JS runner sample (`samples/wasm-js/chat_completion`) runs a single JS file (`entry.mjs`) and exposes `Spear.chat.completions.create`

M2 (tool calling)
- precompiled N tool trampolines + JS `Spear.tool()`
- `AUTO_TOOL_CALL` works with JS handlers
- sample: `samples/wasm-rust/chat_completion_tool_sum`
- sample: `samples/wasm-js/chat_completion_tool_sum`

M3 (audio streaming)
- JS wrappers for `mic`/`rtasr` + `AsyncIterable`
Expand Down
8 changes: 4 additions & 4 deletions docs/rust-sdk-boa-wasm-design-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Rust SDK 需要把这些模式内化,变成对 JS 用户不可见的实现细
- 将 `spear-wasm` 的能力映射到 JS 友好的 API(Promise/Options object)。
- 维护工具回调注册表(JS tool handler 表)。

4) 样例(`samples/wasm-rust/*`)(WASI 可执行)
4) 样例(`samples/wasm-js/*`)(以 JS 为主;通过 Boa JS runner 编译为 WASI 可执行)
- 提供一个轻量 runner:
- 加载用户 JS(内嵌或从 WASI 允许目录读取)
- 创建 Boa `Context`
Expand Down Expand Up @@ -345,18 +345,18 @@ try {
- 参考现有 `tests/wasm_openai_e2e_tests.rs` 的方式,新增 “Boa runtime + chat completion” 的 e2e。
- 样例:
- WASM-C:`samples/wasm-c/*`
- WASM-Rust(Boa runner):`samples/wasm-rust/chat_completion`、`samples/wasm-rust/chat_completion_tool_sum`
- WASM-JS(Boa JS runner):`samples/wasm-js/chat_completion`、`samples/wasm-js/chat_completion_tool_sum`

## 9. 交付拆分(Milestones)

M1(最小可用)
- `spear-wasm-sys` + `spear-wasm` 封装现有 hostcalls
- Rust WASI runner 示例(`samples/wasm-rust/chat_completion`):运行单文件 JS,注入 `Spear.chat.completions.create`
- WASM-JS runner 示例(`samples/wasm-js/chat_completion`):运行单文件 JS(`entry.mjs`),注入 `Spear.chat.completions.create`

M2(工具调用)
- 预置 N 个 tool trampoline + JS `Spear.tool()` 注册
- `AUTO_TOOL_CALL` 跑通 JS 工具函数
- 示例:`samples/wasm-rust/chat_completion_tool_sum`
- 示例:`samples/wasm-js/chat_completion_tool_sum`

M3(音频流)
- `mic`/`rtasr` JS 封装 + `AsyncIterable`
Expand Down
12 changes: 6 additions & 6 deletions docs/samples-build-guide-en.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
## Layout
- Source: `samples/wasm-c/hello.c`
- Source: `samples/wasm-c/chat_completion.c` (Chat Completions sample)
- Source: `samples/wasm-rust/chat_completion/src/main.rs` (Boa JS → Chat Completion)
- Source: `samples/wasm-rust/chat_completion_tool_sum/src/main.rs` (Boa JS → Tool calling)
- Source: `samples/wasm-js/chat_completion/src/main.rs` (Boa JS runner compiled to WASM; runs `entry.mjs` → Chat Completion)
- Source: `samples/wasm-js/chat_completion_tool_sum/src/main.rs` (Boa JS runner compiled to WASM; runs `entry.mjs` → Tool calling)
- Source: `samples/wasm-c/mic_rtasr.c` (realtime mic → realtime ASR)
- Output: `samples/build/hello.wasm`
- Rust outputs: `samples/build/rust/*.wasm`
- WASM-JS outputs: `samples/build/js/*.wasm` (compat: `samples/build/rust/*.wasm`)

## mic_rtasr prerequisites

Expand Down Expand Up @@ -36,11 +36,11 @@ How to run: after building `samples/build/mic_rtasr.wasm`, upload it as a WASM e
- Prefer `zig`: `zig cc -target wasm32-wasi`
- Fallback `clang`: requires `WASI_SYSROOT` pointing to WASI SDK sysroot

Rust samples:
WASM-JS samples:
- Built by `cargo build --release --target wasm32-wasip1`
- Controlled by Makefile vars:
- `BUILD_RUST_SAMPLES=0` to skip Rust samples
- `RUST_SAMPLES="chat_completion chat_completion_tool_sum"` to select which Rust samples to build
- `BUILD_JS_SAMPLES=0` to skip WASM-JS samples (compat: `BUILD_RUST_SAMPLES=0`)
- `JS_SAMPLES="chat_completion chat_completion_tool_sum"` to select which samples to build (compat: `RUST_SAMPLES=...`)

## clang usage
- Environment: `WASI_SYSROOT=/opt/wasi-sdk/share/wasi-sysroot` (adjust as needed)
Expand Down
12 changes: 6 additions & 6 deletions docs/samples-build-guide-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
- 源码:`samples/wasm-c/hello.c`
- 源码:`samples/wasm-c/chat_completion.c`(Chat Completions 示例)
- 源码:`samples/wasm-c/mic_rtasr.c`(实时麦克风→实时ASR示例)
- 源码:`samples/wasm-rust/chat_completion/src/main.rs`(Boa JS → Chat Completion)
- 源码:`samples/wasm-rust/chat_completion_tool_sum/src/main.rs`(Boa JS → tool calling)
- 源码:`samples/wasm-js/chat_completion/src/main.rs`(Boa JS runner 编译为 WASM;内部执行 `entry.mjs` → Chat Completion)
- 源码:`samples/wasm-js/chat_completion_tool_sum/src/main.rs`(Boa JS runner 编译为 WASM;内部执行 `entry.mjs` → tool calling)
- 产物:`samples/build/hello.wasm`
- Rust 产物:`samples/build/rust/*.wasm`
- WASM-JS 产物:`samples/build/js/*.wasm`(兼容:`samples/build/rust/*.wasm`

## mic_rtasr 示例运行前提

Expand Down Expand Up @@ -36,11 +36,11 @@
- 优先使用 `zig`:`zig cc -target wasm32-wasi`
- 备选 `clang`:需要设置 `WASI_SYSROOT` 指向 WASI SDK 的 sysroot

Rust 示例:
WASM-JS 示例:
- 通过 `cargo build --release --target wasm32-wasip1` 构建
- 可通过 Makefile 变量控制:
- `BUILD_RUST_SAMPLES=0` 跳过 Rust 示例构建
- `RUST_SAMPLES="chat_completion chat_completion_tool_sum"` 指定要构建的 Rust 示例列表
- `BUILD_JS_SAMPLES=0` 跳过 WASM-JS 示例构建(兼容:`BUILD_RUST_SAMPLES=0`)
- `JS_SAMPLES="chat_completion chat_completion_tool_sum"` 指定要构建的示例列表(兼容:`RUST_SAMPLES=...`)

## clang 使用说明
- 环境变量:`WASI_SYSROOT=/opt/wasi-sdk/share/wasi-sysroot`(按实际路径)
Expand Down
14 changes: 7 additions & 7 deletions samples/README-en.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This directory contains buildable WASM samples (C + Rust) and their build output
## Layout

- `wasm-c/`: sample sources (C)
- `wasm-rust/`: sample sources (Rust)
- `wasm-js/`: JS-first WASM samples (Boa JS runner compiled to WASM)
- `build/`: build outputs (`.wasm`)

## Build
Expand All @@ -18,7 +18,7 @@ make samples

The build uses `zig` (`zig cc -target wasm32-wasi`) if available; otherwise it falls back to `clang` + `WASI_SYSROOT`.

Rust samples are built with `cargo` for `wasm32-wasip1` (and are copied into `build/rust/`).
WASM-JS samples are built with `cargo` for `wasm32-wasip1` (primary output: `build/js/`, compatibility copy: `build/rust/`).

## Samples

Expand All @@ -28,12 +28,12 @@ Rust samples are built with `cargo` for `wasm32-wasip1` (and are copied into `bu
- `mic_rtasr.c`: mic + realtime ASR sample
- `mcp_fs.c`: MCP filesystem (stdio) tool injection + execution sample

## Rust samples
## JS samples (Boa JS runner compiled to WASM)

- `wasm-rust/chat_completion`: Chat Completion via Boa JS runtime
- Output: `./build/rust/chat_completion.wasm`
- `wasm-rust/chat_completion_tool_sum`: Tool calling (sum) via Boa JS runtime
- Output: `./build/rust/chat_completion_tool_sum.wasm`
- `wasm-js/chat_completion`: executes `entry.mjs` via Boa JS runtime and calls Chat Completion
- Output: `./build/js/chat_completion.wasm`
- `wasm-js/chat_completion_tool_sum`: executes `entry.mjs` via Boa JS runtime for tool calling (sum)
- Output: `./build/js/chat_completion_tool_sum.wasm`

## MCP sample (mcp_fs)

Expand Down
14 changes: 7 additions & 7 deletions samples/README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## 目录结构

- `wasm-c/`:示例源码(C)
- `wasm-rust/`:示例源码(Rust
- `wasm-js/`:以 JS 为主的 WASM 示例(Boa JS runner 编译为 WASM
- `build/`:构建输出(`.wasm`)

## 构建
Expand All @@ -18,7 +18,7 @@ make samples

构建会优先使用 `zig`(`zig cc -target wasm32-wasi`);若未安装 `zig`,则使用 `clang` + `WASI_SYSROOT`。

Rust 示例通过 `cargo build --release --target wasm32-wasip1` 构建,并拷贝到 `build/rust/`。
WASM-JS 示例通过 `cargo build --release --target wasm32-wasip1` 构建,主要输出到 `build/js/`,并兼容拷贝到 `build/rust/`。

## 示例列表

Expand All @@ -28,12 +28,12 @@ Rust 示例通过 `cargo build --release --target wasm32-wasip1` 构建,并拷
- `mic_rtasr.c`:mic + realtime ASR 示例
- `mcp_fs.c`:MCP filesystem(stdio)工具注入与调用示例

## Rust 示例列表
## JS 示例列表(Boa JS runner 编译为 WASM)

- `wasm-rust/chat_completion`:通过 Boa JS 运行时调用 Chat Completion
- 产物:`./build/rust/chat_completion.wasm`
- `wasm-rust/chat_completion_tool_sum`:通过 Boa JS 运行时进行 tool calling(sum)
- 产物:`./build/rust/chat_completion_tool_sum.wasm`
- `wasm-js/chat_completion`:通过 Boa JS 运行时执行 `entry.mjs`,调用 Chat Completion
- 产物:`./build/js/chat_completion.wasm`
- `wasm-js/chat_completion_tool_sum`:通过 Boa JS 运行时执行 `entry.mjs`,进行 tool calling(sum)
- 产物:`./build/js/chat_completion_tool_sum.wasm`

## MCP 示例(mcp_fs)

Expand Down
Binary file modified samples/build/chat_completion.wasm
Binary file not shown.
Binary file added samples/build/js/chat_completion.wasm
Binary file not shown.
Binary file added samples/build/js/chat_completion_tool_sum.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion samples/wasm-c/chat_completion.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static int extract_spear_backend(const char *json, char *out, size_t out_len) {
return 1;
}

//#define SP_ROUTE_OLLAMA_GEMMA3
#define SP_ROUTE_OLLAMA_GEMMA3

int main() {
int32_t fd = sp_cchat_create();
Expand Down
7 changes: 7 additions & 0 deletions samples/wasm-js/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# wasm-js samples

These samples are JS-first: you write JavaScript (e.g. `src/entry.mjs`), and it runs in SPEAR as a WASM executable.

Under the hood, a small Rust “Boa JS runner” is compiled to WASM (`wasm32-wasip1`) and embeds/loads the JS entry.

So the focus here is JS, even though the runner itself is written in Rust.
Loading