Adding self-discoverable AI providers
Register optional provider modules so a Buffaly instance can discover provider catalog rows, provider-native completion executors, and provider-specific authentication without hard-coding them into the host.
Use this with Providers and authentication, which explains provider, transport, model, reasoning, and auth concepts before you modify an installed instance.
Current provider model
Provider implementations live outside the core Buffaly development tree. A running instance discovers optional providers from provider-module assemblies installed under the authoritative runtime install root and listed in ProviderModules.json.
| Concept | Meaning | Examples |
|---|---|---|
| Provider | AI family token. | openai, anthropic, xai, gemini |
| Transport | Execution route. | codex_backend, provider_native |
| Model | Provider-specific model name. | claude-sonnet-4-5, grok-3-mini |
| Reasoning level | Optional model-level setting when supported. | low, medium, high |
Shared contract requirements
External providers must implement the same shared Web.Common contracts as the target Buffaly instance.
Catalog source
IProviderCatalogSource controls whether the provider appears in the UI and catalog APIs.
Completion executor
IProviderNativeCompletionExecutor performs provider-native completions for the provider_native transport.
Auth handler
IProviderAuthHandler is optional, but OAuth-capable providers should implement it for provider-specific login flows.
The provider assembly must reference the same Buffaly.Agent.Web.Common.dll contract version as the target instance. For xAI/Grok, the provider-auth handler owns OIDC discovery and PKCE details while the host owns generic profile lifecycle and stores token bundles under data\sessions\provider-auth\<provider>.
Instance file layout
Provider modules are loaded from the runtime install root. The runtime derives this path from DB-backed Runtime Feature.InstallRootPath; there is no app-base, web-bin, worker-bin, or fallback provider-module probing.
Provider folder
A provider gets its own folder, such as Buffaly.Provider.Anthropic\Buffaly.Provider.Anthropic.dll, under lib\provider-modules.
Web and worker alignment
The web app needs catalog-source assemblies. Worker processes need completion-executor assemblies. Keep web and worker module folders aligned unless deployment tooling does this.
Copy the provider assembly and dependencies, including provider contracts, matching Buffaly.Agent.Web.Common.dll, and provider-specific DLLs. Do not store API keys in provider DLL folders, implementation files, or the provider manifest.
ProviderModules.json
ProviderModules.json registers optional provider components.
| Field | Rule |
|---|---|
| Provider | Stable, unique provider token. |
| AssemblyPath | Relative to the provider-modules directory. |
| CatalogSourceTypeName | Type must implement IProviderCatalogSource. |
| CompletionExecutorTypeName | Type must implement IProviderNativeCompletionExecutor. |
| AuthHandlerTypeName | Optional; OAuth-capable providers should point to an IProviderAuthHandler. |
| Enabled | false keeps the module installed but undiscovered. |
| LoadOrder | Controls deterministic ordering when multiple modules are installed. |
Feature settings rows
Provider credentials and model settings live in the target instance sessions database, not in source. Each provider owns a feature row in dbo.Features.
Provider-specific rows
Anthropic Feature, XAI Feature, and Gemini Feature are critical external-provider rows.
OpenAI/Codex rows
OpenAI through codex_backend also depends on Codex Auth Feature and Codex Backend Feature.
Feature settings commonly include API key or auth profile data, model names, supported reasoning levels, default reasoning level, base URL, provider API version, token limits, and optional separate debug logging. Do not print secret values in prompts, documentation, logs, or commits.
Registration steps
- Build the provider project in the external providers solution.
- Copy the provider module folder into
<InstallRootPath>\lib\provider-modules. - Add or update the provider entry in
ProviderModules.json. - Add or update the provider feature row in the target instance sessions database.
- Recycle only the target instance app pool.
- Verify the provider catalog endpoint shows the provider configured and enabled.
- Verify provider selection persists for a test session.
- Verify an end-to-end completion round trip.
API verification
Use JsonWs endpoints for API-only verification before relying on UI behavior.
Catalog
Call get-provider-catalog. Confirm the provider appears in Providers, IsConfigured=true, IsEnabled=true, and has at least one transport and model.
Selection
Call set-provider-model-selection, then get-provider-selection to verify provider, transport, model, and reasoning persisted for the test session.
Completion
Call evaluate with a small smoke instruction. Expect completed status and the exact assistant response in the transcript.
Provider response contract
Provider-native executors must return Buffaly canonical items JSON in ProviderNativeCompletionResult.Raw. A successful smoke response should become a message item with role assistant, phase final_answer, output_text content, and display-message metadata.
If a third-party model returns a canonical Buffaly items payload as text or inside a closed JSON code block, the provider boundary should unwrap and validate only complete JSON objects whose root contains an items array. Otherwise, preserve ordinary text and wrap it as output_text.
Common failure modes
Provider does not appear
- Manifest not copied to the install-root provider-modules folder.
- Wrong assembly path or type name.
- Mismatched
Buffaly.Agent.Web.Common.dll. - Feature row missing, disabled, or invalid.
Provider appears unconfigured
- Feature row exists but credentials/settings are missing.
- Provider code reads a different feature name.
- Settings JSON does not match the provider contract.
Selection fails
- Provider token mismatch.
- Model is not in the provider catalog row.
- Reasoning level is unsupported for that model.
- Target app pool needs recycle.
Completion fails
- Provider DLL missing from worker folder.
- API key invalid or provider rejects the model.
- Response mapper does not produce canonical Buffaly items JSON.
- Worker cannot access runtime resources due to app pool identity/profile settings.
Operator notes from validation
- Reasoning levels are model-specific. Do not pass
low,medium, orhighunless the provider catalog row declares support. - The provider catalog can show an error while still returning configured providers. Inspect both
Providersand the top-levelErrorfield. - Live model availability should be verified against the provider model endpoint and with a completion smoke test.
- App pool identity/profile settings can affect worker access to runtime resources such as named global mutexes.