-
Notifications
You must be signed in to change notification settings - Fork 60
Support per-session/per-agent instances with persistent Store lifetime #615
Description
Summary
Currently, Wassette creates a fresh Store for each tool call, which means all WebAssembly linear memory state is reset between calls. This proposal requests an optional mode where a Store can persist across multiple calls within a session or agent context.
Motivation
1. Consistent Multi-Turn MCP Tool Calls
Many MCP tools benefit from maintaining state across a conversation. For example:
- A database query tool that keeps a connection pool
- A stateful interpreter (Python REPL, shell session)
- A tool that accumulates context or learns from previous calls
Currently, each call_tool invocation starts fresh, making it impossible for the WASM component to maintain any in-memory state between calls from the same agent.
2. Per-Instance MCP Resources
MCP's resources capability allows servers to expose data that clients can read. Resources often represent stateful entities:
- File handles or cursors
- Session-specific data
- Cached computation results
With per-call Store isolation, resource state cannot persist, limiting the expressiveness of WASM-based MCP servers.
3. Efficient Resource Utilization
Some components perform expensive initialization (loading models, parsing large configs, establishing connections). Re-doing this on every call is wasteful when multiple calls will be made within the same agent session.
Current Architecture
Wassette already optimizes compilation via InstancePre:
pub struct ComponentInstance {
component: Arc<Component>,
instance_pre: Arc<InstancePre<WassetteWasiState<WasiState>>>,
// ...
}But in execute_component_call(), a fresh Store is created per call:
let mut store = Store::new(self.runtime.as_ref(), state);
let instance = component.instance_pre.instantiate_async(&mut store).await?;
func.call_async(&mut store, &argument_vals, &mut results).await?;
// Store dropped here - state lostProposed Solution
Add an optional session/agent-scoped instance mode:
- Session Registry: Maintain a map of
(session_id, component_id) -> (Store, Instance) - Lifecycle Hooks:
create_session(session_id)- instantiate components for a sessiondestroy_session(session_id)- clean up Stores- Or automatic cleanup via TTL/LRU
- Execution Mode: New method like
execute_component_call_in_session(session_id, ...)that reuses the existing Store
This would be opt-in, preserving the current stateless behavior as the default for security-sensitive use cases.
Alternatives Considered
- External state via WASI APIs: Components could use
wasi:keyvalueor similar, but this externalizes state management and adds complexity for simple in-memory use cases. - Component-managed serialization: Components could serialize/deserialize state on each call, but this is inefficient and burdensome for component authors.
Use Case Example
An agentic runtime instantiates multiple agents, each with their own MCP server connections. With per-session instances:
- Agent A's calls to a "notes" tool accumulate in Agent A's memory
- Agent B gets a separate instance with its own state
- Component compilation remains shared across all agents
Disclosure: This issue was drafted with assistance from Claude (AI).