-
Notifications
You must be signed in to change notification settings - Fork 92
Description
I wanted to write up something quick, and am happy to expand on the request if there's any interest in doing so.
The short of it is that I believe a number of use cases could benefit from first-class modules.
What do I mean by first-class module? Simply the ability to invoke multiple implementations of a Component Model world from within the same application, in a way that leverages and builds upon the component model ABI.
Note that this is already possible host-side: if you are embedding wasmtime in your application -- let's say, for purposes of discussion, an API gateway with WASM-based extension points -- then you can dynamically load, compile, and execute any number of instances of components with the same set of exports.
However, this same capability is not possible guest-side. Meaning, if you were writing a component model application, although you have the ability to statically link against a single implementation of a world and invoke any of its exports, you do not have the ability to invoke exports across multiple distinct implementations of the world, even with arbitrary host support.
Now here, I am not suggesting that the component model support dynamic linking, because even though that could be useful, it's a separate discussion and is not actually necessary for achieving what I want.
Rather, I am suggesting there is a smaller, better scoped feature, which I am calling first-class modules (for lack of a better name), which gets us enough of the way toward my end-goal, that the rest can be done in the host.
What would a first-class module be? Well, I believe it would be some kind of resource (instance resource?), which would be created and exposed via the host (e.g. load-plugin()
), which conceptually represents an instance of a component, and in which there is first-class support for invoking the statically-known exports on this instance. One can imagine many different ways to make this possible, but conceptually, you could imagine that functions could return worlds (such as load-plugin
, defined in the host, returning a plug-in world as an instance resource), and then invoke special built-in functions to invoke any of the world exports on a given instance resource.
For us at Golem, this feature set would open up the door to many things, but in particular, it would enable us to perform instance-to-instance communication in a clean and elegant way.
Currently, in order to support the use case of one instance (source) communicating to another instance (target) in a type-safe way, we first pre-process the WIT representing the interface of the target component, turning every interface into a resource, whose constructor accepts the location or identity of the target instance (and turning every existing resource into a new resource, with an additional constructor parameter). Then the instance is actually statically linked against the transformed WIT, which is dynamically implemented in the host.
This gives us type-safe instance-to-instance communication, but at great cost, due to the complications involved.
With something like first-class modules, instance-to-instance communication becomes incredibly simple and ergonomic for developers. But many other use cases are possible, including:
- Use of plug-ins on the guest side (where instances of plug-ins is still securely provided via the host)
- Plug-ins are interesting because you have many of them with the same interface all running in your app in the same time, and you really want to be able to invoke them in a type-safe way without embedding your own ABI protocol
- Allowing gRPC where you can communicate with different servers exporting the same services
- Supporting MCP protocol where an agent may need to interact with multiple servers all supporting the same interface
- Etc.