Chat Client Provider
The IChatClientProvider interface is the bridge between the AI conversation service and your AI backend.
Default Behavior
Section titled “Default Behavior”By default, a built-in InjectedChatClientProvider is registered that resolves IChatClient from your DI container. For most apps, simply register an IChatClient and you’re done:
builder.Services.AddChatClient(new OpenAIClient("your-api-key").GetChatClient("gpt-4o").AsIChatClient());
builder.Services.AddShinyAiConversation(opts =>{ // No need to call SetChatClientProvider — the default resolves IChatClient from DI});If no IChatClient is registered and no custom provider is set, an InvalidOperationException is thrown at runtime.
Built-in Providers
Section titled “Built-in Providers”Two ready-made providers are available as separate NuGet packages so you don’t have to implement IChatClientProvider yourself.
Shiny.AiConversation.OpenAi
Section titled “Shiny.AiConversation.OpenAi”A static provider for any OpenAI-compatible endpoint (OpenAI, Azure OpenAI, Ollama, etc.). Creates the client once at startup with logging and function invocation middleware.
dotnet add package Shiny.AiConversation.OpenAibuilder.Services.AddShinyAiConversation(opts =>{ opts.AddStaticOpenAIChatClient( apiToken: "your-api-key", endpointUri: "https://api.openai.com/v1", modelName: "gpt-4o" );});Works great for Blazor WASM, server apps, or any MAUI app where you have an API key up front.
Shiny.AiConversation.Maui.GithubCopilot
Section titled “Shiny.AiConversation.Maui.GithubCopilot”A MAUI-specific provider that authenticates via the GitHub OAuth device code flow and uses the Copilot API for chat completions. The entire authentication experience is self-contained:
- When authentication is needed, a popup appears with the device code
- The code is automatically copied to the clipboard
- The user presses OK and a browser opens to GitHub’s verification page
- The provider polls in the background until the user authorizes
- The OAuth token is exchanged for a Copilot API token and cached
- Tokens are persisted in
SecureStorageacross app restarts
dotnet add package Shiny.AiConversation.Maui.GithubCopilotbuilder.Services.AddShinyAiConversation(opts =>{ opts.AddGithubCopilotChatClient();});No login page, token storage, or event wiring needed — one line of registration handles everything.
Additional API on GitHubCopilotChatClientProvider:
| Member | Description |
|---|---|
IsAuthenticated | Whether a stored token exists |
StartAuthentication(ct) | Manually trigger the device code flow |
CancelAuthentication() | Cancel an in-progress auth flow |
SignOut() | Clear stored tokens |
AccessTokenChanged | Event fired when auth state changes (token or null) |
Custom Implementation
Section titled “Custom Implementation”For scenarios not covered by the built-in providers, implement IChatClientProvider:
Interface
Section titled “Interface”public interface IChatClientProvider{ Task<IChatClient> GetChatClient(CancellationToken cancelToken = default);}The service calls GetChatClient() before each chat request, so your implementation can handle token refresh, re-authentication, or client rotation.
Registration
Section titled “Registration”builder.Services.AddShinyAiConversation(opts =>{ opts.SetChatClientProvider<MyChatClientProvider>();});Example: Ollama (Local)
Section titled “Example: Ollama (Local)”using Microsoft.Extensions.AI;using Shiny.AiConversation;
public class OllamaChatClientProvider : IChatClientProvider{ public Task<IChatClient> GetChatClient(CancellationToken cancelToken = default) { var client = new OllamaChatClient( new Uri("http://localhost:11434"), "llama3.1" ); return Task.FromResult<IChatClient>(client); }}Authentication Patterns
Section titled “Authentication Patterns”| Pattern | Provider |
|---|---|
| API key from config | AddStaticOpenAIChatClient() or register IChatClient in DI |
| GitHub Copilot (device code flow) | AddGithubCopilotChatClient() |
| Managed identity / custom | Implement IChatClientProvider |
| Token refresh with caching | Implement IChatClientProvider |