Generates the provider pattern (interface plus fake/real implementations) for plugin data sources. Use when the user says "create a provider for [data source]", "add provider interface for [feature]", or "implement provider pattern for [plugin]".
Generates provider interface and implementations under src/Plugins/Providers/. Follow project conventions from existing providers (e.g. IWeatherDataProvider, IOutlookEmailProvider).
Before generating files, gather:
Provider name and purpose
I[Name]DataProvider or I[Name]Provider if the domain is not "data" (e.g. IOutlookEmailProvider).Methods needed
Task<T> / Task<T?> for async).OutlookEmail in IOutlookEmailProvider.cs).Which artifacts
Only generate the Interface and the implementations the user requested.
| Artifact | Path | Namespace |
|---|---|---|
| Interface | src/Plugins/Providers/Interfaces/I[Feature]DataProvider.cs | AnimalAI.Plugins.Providers |
| Fake | src/Plugins/Providers/Fake/Fake[Feature]DataProvider.cs | AnimalAI.Plugins.Providers |
| Real | src/Plugins/Providers/Real/Real[Feature]DataProvider.cs | AnimalAI.Plugins.Providers |
Use I[Feature]DataProvider / Fake[Feature]DataProvider / Real[Feature]DataProvider unless the domain uses another suffix (e.g. IOutlookEmailProvider → FakeOutlookEmailProvider, RealOutlookEmailProvider).
AnimalAI.Plugins.ProvidersTask<T> or Task<T?>OutlookEmail) in the same file as the interface when they are specific to that providernamespace AnimalAI.Plugins.Providers;
/// <summary>
/// Interface for [purpose].
/// </summary>
public interface I[Feature]DataProvider
{
/// <summary>[Description]</summary>
/// <param name="...">...</param>
/// <returns>...</returns>
Task<ReturnType> MethodNameAsync(...);
}
Dictionary, static fields, or hard-coded lists)Task.FromResult(...) for sync data, or Task.FromResult for trivial asyncnamespace AnimalAI.Plugins.Providers;
/// <summary>
/// Fake [feature] data provider that returns mock data for testing.
/// </summary>
public class Fake[Feature]DataProvider : I[Feature]DataProvider
{
public Task<ReturnType> MethodNameAsync(...)
{
// Return mock data; use Task.FromResult(...) if no real async work
return Task.FromResult(...);
}
}
HttpClient / HttpClient.GetFromJsonAsync or other real I/O as needed[JsonPropertyName("...")] if requirednull or a safe default per existing convention (e.g. RealWeatherDataProvider returns null on failure)using System.Net.Http.Json;
using System.Text.Json.Serialization;
namespace AnimalAI.Plugins.Providers;
/// <summary>
/// Real [feature] data provider that uses [API/service].
/// </summary>
public class Real[Feature]DataProvider : I[Feature]DataProvider
{
private static readonly HttpClient HttpClient = new();
public async Task<ReturnType> MethodNameAsync(...)
{
try
{
// Call external API; map response to interface return type
return ...;
}
catch
{
return null; // or default; match existing Real* style
}
}
}
In the plugin class under src/Plugins/Base/SK/:
ILoggerFactory? as the first optional parameter.#region Provider Fields
private readonly I[Feature]DataProvider _dataProvider;
#endregion Provider Fields
#region Constructors
public [Feature]Plugin(ILoggerFactory? loggerFactory = null, I[Feature]DataProvider? dataProvider = null)
{
_dataProvider = dataProvider ?? new Fake[Feature]DataProvider();
_logger = loggerFactory?.CreateLogger<[Feature]Plugin>();
}
#endregion Constructors
Use _dataProvider inside kernel functions instead of calling external APIs directly.
To choose fake vs real at runtime (e.g. in StandardKernel or a nested plugin), follow the Outlook pattern:
KernelConstants or appsettings), e.g. [Feature]ApiKey or [Feature]ServiceUrl.// Uses Real[Feature]DataProvider if config is set, otherwise Fake for testing
I[Feature]DataProvider provider = string.IsNullOrEmpty(KernelConstants.[Feature]ConfigKey)
? new Fake[Feature]DataProvider()
: new Real[Feature]DataProvider(KernelConstants.[Feature]ConfigKey);
var plugin = new [Feature]Plugin(loggerFactory, provider);
KernelConstants, add something like:/// <summary>
/// [Purpose]. Leave empty to use fake data for testing.
/// </summary>
public const string [Feature]ConfigKey = "";
Show this conditional pattern and, if applicable, the KernelConstants addition in the “how to inject” / “how to switch fake vs real” part of the answer.
src/Plugins/Providers/Interfaces/IOutlookEmailProvider.cssrc/Plugins/Providers/Interfaces/IWeatherDataProvider.cssrc/Plugins/Providers/Fake/FakeWeatherDataProvider.cs, FakeOutlookEmailProvider.cssrc/Plugins/Providers/Real/RealWeatherDataProvider.cssrc/Plugins/Base/SK/WeatherPlugin.cs, OutlookEmailPlugin.cssrc/AnimalKernel/Core/StandardKernel.cs (search for IOutlookEmailProvider / FakeOutlookEmailProvider)AnimalAI.Plugins.Providers.ILoggerFactory? then I[Feature]DataProvider? and defaults provider to new Fake[Feature]DataProvider() when null.KernelConstants (or config) change.