Skip to content

RFC: Backend provider plugins #24

Description

@p-e-w

With the basic plugin system now landed (ffaf2b6), and @Piktrip's excellent work on OpenRouter integration (#23) as a starting point, it's time to make it possible for plugins to provide backends that Waidrin can use for inference. The main challenges are being generic enough to serve all possible plugins of this type, and maintaining a clean engine/frontend separation.

Here's my current plan to achieve this:

The engine interface

Waidrin's engine relies on just two functions to communicate with the LLM: getResponse, and getResponseAsObject. The logical first step would be to extract those function's signatures (without the params, as those aren't generic) into a Backend TypeScript interface. The plugin would then provide an implementation of this interface, or, better, any number of them, as a plugin might want to provide multiple backends:

type Plugin = {
  ...
  getBackends(): Promise<Record<string, Backend>>;
};

The response is a map from the backend name to the implementation, and can contain arbitrarily many entries. When the plugin is loaded, the loader checks whether it implements getBackends, and, if it does, calls it and adds the resulting backend entries to a Record<string, Backend> map in the global state. The state also contains an activeBackend: string field that decides which of the backends is used by the engine.

The frontend

The Plugin interface is frontend-agnostic. Any frontend-specific logic is handled by the opaque context parameter passed to init. The context provides environment-specific functionality to the plugin, and for Waidrin's React frontend, will contain various functions that allow the plugin to interact with it.

My idea is to add something like the following function to the context:

addBackendConfigurationPage(backendName: string, displayName: string, pageComponent: () => React.ReactNode): void

When the plugin calls that function, Waidrin adds a new tab to the connection screen, titled displayName, with pageComponent as its contents. The plugin is free to do whatever it wants in this component, and can connect it to the Backend implementation it provides in whatever way it wants. When the user selects this tab, Waidrin sets activeBackend to backendName, and everything should magically work. This way, plugins can provide any number of backend implementations, and separate configuration pages for each of them, while activation is completely controlled by the application. Waidrin's plugin system already has a rudimentary mechanism for plugin-specific settings, which can be used and extended as needed to serve backend plugins.

Backend provider plugins will be a critical feature making Waidrin usable by more people, and it's very important to get them right. If you have any comments on this proposal, now is the time!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions