-
Notifications
You must be signed in to change notification settings - Fork 58
Open
Labels
enhancementNew feature or requestNew feature or requestquestionFurther information is requestedFurther information is requested
Description
Problem
Currently, Wassette components can maintain state across tool calls (like memory-js), but they cannot run code between tool calls. This prevents use cases like:
- Starting an HTTP server that listens while the LLM does other work
- Running background workers that produce output over time
- Any tool that needs to "stay alive" between invocations
Example scenario:
1. LLM calls: spawn("flask_server_code") → returns process_id=42
2. LLM thinks, makes HTTP requests to localhost:8080
3. LLM calls: read-stdout(42) → expects server logs
This doesn't work today because the component is frozen between calls - the Flask server never actually runs.
Root Cause
Wassette uses wasmtime's async_support(true) for non-blocking host I/O, but doesn't use wasmtime's background task primitives (Accessor::spawn, StoreContextMut::spawn). The component only executes during a tool call, not between them.
Proposed Solution
Add host-provided imports for background process management. Components would call these host functions rather than trying to run code inside WASM:
interface process-manager {
type process-id = u64;
enum signal {
terminate, // SIGTERM
kill, // SIGKILL
}
variant process-state {
running,
exited(u32),
signaled(signal),
}
variant process-error {
invalid-code(string),
not-found,
not-running,
resource-exhausted,
}
/// Start a background process (host spawns real thread/process)
spawn: func(runtime: string, code: string) -> result<process-id, process-error>;
/// Check process state
state: func(id: process-id) -> result<process-state, process-error>;
/// Send termination signal
signal: func(id: process-id, sig: signal) -> result<_, process-error>;
/// Read buffered stdout
read-stdout: func(id: process-id) -> result<string, process-error>;
/// Read buffered stderr
read-stderr: func(id: process-id) -> result<string, process-error>;
/// List all process IDs
list: func() -> list<process-id>;
}Key design points:
- Host (Wassette) manages real OS processes/threads, not WASM execution
- Components just hold process IDs and call host functions
- Fits Wassette's deny-by-default security model (new capability to grant)
runtimeparameter allows different interpreters (python, node, etc.)
Implementation Approaches
- Host-side OS processes: Wassette spawns actual subprocesses for each
spawn()call - Wasmtime
Accessor::spawn: Use wasmtime's concurrent task API to run interpreters in background - Hybrid: Lightweight tasks via wasmtime, heavy processes via OS
Use Cases
- AI coding agents: Start a dev server, test it, then shut it down
- Data pipelines: Run background ETL jobs while agent monitors progress
- Interactive tools: REPLs, debuggers, or any stateful CLI tool
Questions for Maintainers
- Does this align with Wassette's goals?
- Would this be better as a core feature or a separate "process" capability?
- Any concerns about security model (sandboxing spawned processes)?
- Interest in a PR, or should this wait for WASI 0.3 async?
Related
- WASI Issue #414: posix_spawn API
- Wasmtime Accessor::spawn
- WASI Preview 3 async roadmap (mid-2025)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestquestionFurther information is requestedFurther information is requested