Plugin Context
Last updated:
AgentPluginContext is the supported bridge between the host and plugin contribution factories. It provides credential resolution, HTTP clients, logging, time-zone information, tracked asset downloads, the plugin deployment directory, and the host-owned model storage root without exposing the host service provider.
Note
Toolset factories receive a user-scoped context. Model and speech provider factories receive a startup context with HTTP, logging, and tracked-download capabilities, but its credential resolver always returns null.
Use the supplied capabilities
| Member | Capability |
|---|---|
CredentialResolver |
Resolves only credential keys declared by this plugin's registered contributions in a user scope. Provider contexts expose no credential values. |
CreateHttpClient(string name) |
Creates a host-managed named HttpClient. |
LoggerFactory |
Creates loggers that use the host logging pipeline. |
UserTimeZone |
The user's selected TimeZoneInfo in a toolset context. Provider contexts use the host's local time zone. |
PluginDirectory |
The read-only directory containing the current plugin's manifest and deployed files. |
ModelStorageDirectory |
The host-owned writable root under which providers can create their own model directory. |
EnsureDownloadAsync(...) |
Starts or joins a host-tracked asset download using the existing progress and cancellation services. |
Register a factory in IAgentPlugin.Configure and pass only the capabilities the toolset needs:
public void Configure(AgentPluginBuilder builder)
{
builder.AddToolset(context => new NewsToolset(
context.CredentialResolver,
context.CreateHttpClient(nameof(NewsToolset)),
context.LoggerFactory.CreateLogger<NewsToolset>(),
context.UserTimeZone));
}
Provider factories use the same context shape for host-managed HTTP and logging:
builder.AddModelProvider(context => new ExampleModelProvider(
context.CreateHttpClient(nameof(ExampleModelProvider)),
context.LoggerFactory.CreateLogger<ExampleModelProvider>()));
Provider operations receive any selected plaintext API key through the existing apiKey parameter on the provider interface. Do not resolve user credentials in a provider factory.
Treat PluginDirectory as deployment content. Do not write models, settings, or caches beside plugin binaries. Create a provider-specific child directory under ModelStorageDirectory instead of inferring the host's application-data layout.
Pass the provider-owned destination path to EnsureDownloadAsync(...) when an asset is missing. Oscova remains responsible for tracking progress and cancellation. The plugin supplies only the stable operation ID, source URL, destination path, and cancellation token.
CreateHttpClient preserves host HTTP-client configuration and policies. The logical name selects named configuration when one exists. An otherwise unconfigured name still uses the host defaults. Do not create a separate static client to bypass this path.
Follow contribution lifetimes
The plugin entry point registers contribution factories once when the assembly loads. Oscova creates one provider context per loaded plugin and shares it among that plugin's provider factories. For each user scope, Oscova creates a separate context per plugin and shares it among that plugin's toolset factories.
- Do not store
AgentPluginContextor a toolset instance in static state. - Do not share a context between users.
- Do not share a context between plugins.
- Resolve credentials when the tool runs so rotations and missing values are observed.
- Keep the factory quick and free of remote calls or background work.
- Retain only the supplied client, logger, resolver, or time zone needed by that toolset.
- A successfully activated provider can implement
IDisposablewhen it owns native or other synchronous resources. Oscova disposes it during host shutdown.
The context is a capability boundary, not a process or security boundary. Plugin code remains trusted in-process code and can use .NET APIs outside the context. Enabling a plugin therefore requires the same trust review described in Plugin Manifest.
Resolve credentials safely
IToolCredentialResolver returns null when a credential or field is unavailable or the requested key was not declared by that plugin's registered toolset and provider types. An undeclared key is rejected before the credential store is queried. Both overloads accept cancellation:
Task<string?> ResolveAsync(
string credentialKey,
CancellationToken ct = default);
Task<string?> ResolveAsync(
string credentialKey,
string fieldName,
CancellationToken ct = default);
Use the first overload for a single-field credential and the second for a named field. Never put resolved secret values in logs, exceptions, or tool results. Return a clear setup message when a required value is missing.
Handle initialization failures
If a toolset factory throws, that contribution is not added to the affected user's tool collection. This is separate from manifest loading, so validate normal user setup, credentials, and remote availability when the tool runs instead of throwing from the factory.
Use LoggerFactory for operational failures and include non-secret context such as the plugin, tool, credential key, or remote service. Pass the tool call's cancellation token to credential and network operations.
Construct a context in tests
Tests and custom hosts can create a context directly. The full constructor requires all five services and both fully qualified directory paths:
var context = new AgentPluginContext(
credentialResolver,
httpClientFactory,
loggerFactory,
userTimeZone,
pluginDirectory,
modelStorageDirectory,
ensureDownloadAsync);
The three-argument convenience constructor remains suitable when tracked downloads are not needed. Calling EnsureDownloadAsync(...) on that context throws NotSupportedException instead of silently ignoring the request.
Troubleshooting
- Credential is always null: verify the credential key is declared directly on a registered contribution, then check the field name and resolve it at call time for the current user.
- Requests use unexpected defaults: check the name passed to
CreateHttpClient. Only configured names receive name-specific settings. - Tool is missing for one user: make sure the factory does not throw while that user's tool collection is assembled.
- Times use the server zone: use
context.UserTimeZoneinstead ofTimeZoneInfo.Localin production toolsets. - Tracked downloads are unavailable: use the full constructor in a custom host and supply its download operation.