Skip to content
Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More

Chat Client Provider

The IChatClientProvider interface is the bridge between the AI conversation service and your AI backend.

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.

For advanced scenarios (on-demand authentication, token refresh, re-authentication on 401), implement IChatClientProvider:

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.

builder.Services.AddShinyAiConversation(opts =>
{
opts.SetChatClientProvider<MyChatClientProvider>();
});
using Microsoft.Extensions.AI;
using OpenAI;
using Shiny.AiConversation;
public class OpenAiChatClientProvider(IConfiguration config) : IChatClientProvider
{
public Task<IChatClient> GetChatClient(CancellationToken cancelToken = default)
{
var client = new OpenAIClient(config["OpenAI:ApiKey"]);
return Task.FromResult(
client.GetChatClient("gpt-4o").AsIChatClient()
);
}
}

Example: GitHub Copilot (Device Code Flow)

Section titled “Example: GitHub Copilot (Device Code Flow)”

The sample apps include a full GitHub Copilot implementation that demonstrates:

  • OAuth 2.0 device code flow for authentication
  • Copilot API token exchange and caching
  • Custom HTTP pipeline policy for required headers
  • Automatic re-authentication on 401 responses
public class GitHubCopilotChatClientProvider : IChatClientProvider
{
public async Task<IChatClient> GetChatClient(CancellationToken cancelToken = default)
{
var copilotToken = await GetCopilotToken(cancelToken);
var options = new OpenAIClientOptions
{
Endpoint = new Uri("https://api.githubcopilot.com")
};
// Copilot API requires editor identification headers
options.AddPolicy(new CopilotHeadersPolicy(), PipelinePosition.PerCall);
var client = new OpenAIClient(
new ApiKeyCredential(copilotToken),
options
);
return client.GetChatClient("gpt-4o").AsIChatClient();
}
}

See the full implementation in the MAUI sample or Blazor sample.

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);
}
}

Your provider can handle authentication however you need:

PatternWhen to use
API key from configSimple server-side apps
OAuth device code flowMobile apps needing user login
Managed identityAzure-hosted services
Token refresh with cachingAny provider with expiring tokens

The service calls GetChatClient() on every request, so you can cache the client and refresh tokens transparently.