Plugin Builder
Last updated:
Use AgentPluginBuilder inside IAgentPlugin.Configure to declare the toolset and provider factories an enabled plugin contributes to Oscova.
Note
The builder records registrations. It does not create toolsets, start providers, resolve credentials, or call remote services while Configure runs.

Supported registrations
AgentPluginBuilder exposes four registration methods:
| Method | Type requirement | What the builder stores |
|---|---|---|
AddToolset<TToolset>(Func<AgentPluginContext, TToolset>) |
TToolset is a class implementing ICrewToolset |
The toolset type and factory |
AddModelProvider<TProvider>(Func<AgentPluginContext, TProvider>) |
TProvider is a class implementing IModelProvider |
The provider type and factory |
AddSpeechRecognitionProvider<TProvider>(Func<AgentPluginContext, TProvider>) |
TProvider is a class implementing ISpeechRecognitionProvider |
The provider type and factory |
AddSpeechSynthesisProvider<TProvider>(Func<AgentPluginContext, TProvider>) |
TProvider is a class implementing ISpeechSynthesisProvider |
The provider type and factory |
Each method returns the same builder, so registrations can be chained:
using System.ComponentModel;
using Oscova.Agents;
using Oscova.Agents.Plugins;
public sealed class ExampleAgentPlugin : IAgentPlugin
{
public void Configure(AgentPluginBuilder builder)
{
builder.AddToolset(_ => new ExampleToolset());
}
}
public sealed class ExampleToolset : ICrewToolset
{
[DisplayName("example_echo")]
[Description("Returns the supplied text unchanged.")]
public static string Echo(string text)
{
return text;
}
}
Chain AddModelProvider, AddSpeechRecognitionProvider, or AddSpeechSynthesisProvider after AddToolset when the plugin implements those provider interfaces. These are the complete public builder registrations. There is no supported builder registration for middleware, background services, routes, settings pages, or arbitrary host services.
Toolset lifecycle and naming
AddToolset requires a non-null factory, and that factory must return a non-null toolset. Oscova calls the factory once while assembling each user scope and passes an AgentPluginContext for that user. A toolset can serve multiple runs in that user scope, so keep run-specific state inside each method call.
Return a new toolset when it depends on credentials, HTTP clients, logging, or the user's time zone. Do not cache the context, resolver, or toolset in static state. Treat clients returned by CreateHttpClient as host-managed and do not dispose them from the toolset.
Plugin tool methods use the same reflection contract as built-in toolsets:
- Public methods declared directly on the toolset type become tools.
[DisplayName]supplies the base tool name. Without it, the method name is used.[Description],[ToolPolicy], and[ToolNetworkScope]provide optional metadata.- Default approval is
ToolApprovalMode.Default. - Default network scope is
NetworkScope.None.
The qualified wire name begins with the plugin manifest ID, followed by the toolset owner and tool name. The owner is the class name with a trailing Toolset removed. Every segment is normalized. For example, plugin acme.search, class ExampleToolset, and display name search_records produce acme_search__example__search_records.
Provider lifecycle
The three provider methods register factories. Oscova invokes them during startup and shares the resulting providers across users. All provider factories from one plugin receive the same AgentPluginContext. Factories from different plugins receive different contexts. Use CreateHttpClient and LoggerFactory for supported host capabilities. The provider context does not expose user credential values.
Keep contributed providers stateless and thread-safe. Runtime calls receive provider configuration, the selected plaintext API key, and cancellation through the corresponding public provider interface.
A model provider can implement IModelDownloadProvider when its SDK owns model acquisition. Oscova then offers the provider's catalog models for download in the provider editor and calls DownloadModelAsync with progress and cancellation. Return true from IModelProvider.DefaultIsLocalEndpoint only when the provider is local by design. A saved endpoint-scope choice still takes precedence.
A successfully activated provider can implement IDisposable when it owns synchronous resources. Oscova disposes those providers during host shutdown. Plugins still cannot register background services or arbitrary shutdown callbacks.
Provider Type values are stable product identifiers. Use a unique value for each model, recognition, or synthesis provider. Built-in speech providers take precedence over plugin providers with the same Type. Among speech plugins, the first provider registered for a Type is retained and each later collision produces an operator warning naming the dropped implementation.
Speech routing
SpeechRecognitionRouter and SpeechSynthesisRouter resolve the exact registered provider whose Type matches the supplied SpeechProviderConfig. A host selects the configuration and supplies the resolved API key, offline requirement, download URL, and session input needed by each operation. The routers reject non-local endpoints when offline operation is required, before calling the provider.
SpeechProviderKeys is a non-exhaustive set of well-known identifiers, not an allowlist. Choose a stable, unique type for your plugin provider and register it through the builder. It routes without adding a framework constant.
Ordering and duplicates
A new builder starts with four empty collections. It appends registrations in call order and exposes them through read-only lists:
ToolsetsModelProvidersSpeechRecognitionProvidersSpeechSynthesisProviders
The builder does not deduplicate registrations. Register each contribution once. Repeated toolsets can produce duplicate qualified tool names, which Oscova rejects instead of replacing the earlier tool. Model-provider duplicate behavior remains host-owned. For speech providers, Oscova retains built-ins before plugins and retains the first plugin contribution when plugins collide, logging each dropped implementation.
Failure behavior
- A null contribution factory throws
ArgumentNullExceptionduringConfigure. - A factory that returns null cannot produce a valid toolset and fails when Oscova publishes the tools.
- If
Configurethrows, the plugin is skipped and a load diagnostic is recorded. - If a toolset factory throws for one user scope, that contribution is skipped for that user and the failure is logged.
- If a provider factory throws or returns null, that provider is skipped and the failure is logged.
- Thrown factory and provider-construction failures are isolated, so later contributions are still attempted.
- Invalid reflected metadata or duplicate qualified tool names are publication errors, not user-setup failures.
Keep expected setup failures, such as a missing credential or unavailable remote service, inside the tool or provider operation. Return actionable guidance for user-correctable failures and honor the supplied cancellation token.
The builder has no disposal or background-service registration. Do not start background work or create resources that need a plugin-specific shutdown callback.