| name | shiny-aiconversation |
| description | Generate code for Shiny.AiConversation - a centralized AI service library for .NET MAUI apps with chat client abstraction, wake word detection, speech-to-text/text-to-speech, acknowledgement modes (None/AudioBlip/LessWordy/Full), persistent message store, optional AI chat history lookup tool, and configurable sound effects |
| when_to_use | Use when the user needs a .NET MAUI AI conversation service, chat client provider setup, persistent message storage, wake-word or speech-driven conversations, GitHub Copilot/OpenAI chat integration, or voice-selection tools. |
| triggers | ["Set up an AI chat service in a .NET MAUI app","Register and configure IAiConversationService with dependency injection","Implement IChatClientProvider for a specific AI backend (OpenAI, GitHub Copilot, Azure, etc.)","Implement IMessageStore for persistent chat history","Add wake word detection to an app","Configure acknowledgement modes (None, AudioBlip, LessWordy, Full)","Set up sound effects for AI state transitions","Configure voice interruption with quiet words","Set up speech-to-text and text-to-speech options (culture, voice, speech rate, etc.)","Add the optional ChatLookupAITool for AI-driven history search","Enable voice selection tools so the AI can list voices, play samples, and switch its own voice","Build a chat UI that integrates with IAiConversationService","Handle AI state changes (Idle, Listening, Thinking, Responding)","Use TalkTo or ListenAndTalk for AI interactions","Check speech/microphone access before starting voice features"] |
Shiny.AiConversation Skill
Reference Docs
reference/ai-service.md - Service orchestration, lifecycle, and configuration details
reference/registration.md - DI registration patterns and setup options
reference/message-store.md - IMessageStore guidance and persistence patterns
reference/chat-client-provider.md - IChatClientProvider implementation guidance
reference/chat-lookup-tool.md - AI chat-history lookup tool behavior
reference/voice-selection-tools.md - Voice discovery, preview, and switching tools
You are an expert in the Shiny.AiConversation library, a centralized AI service for .NET MAUI applications that integrates chat, speech recognition, wake word detection, text-to-speech, and persistent message storage.
Library Overview
NuGet: Shiny.AiConversation
Namespace: Shiny.AiConversation
Infrastructure Namespace: Shiny.AiConversation.Infrastructure (internal implementations)
The library provides:
- IAiConversationService: Central orchestrator for AI interactions — manages access checking, state (Idle/Listening/Thinking/Responding), wake word detection, speech-to-text capture, chat client communication, text-to-speech response, acknowledgement modes, sound effects, persistent chat history, conversation continuation (auto-listens when AI asks a question), and voice interruption (quiet words to stop TTS, or speak over the AI to redirect the conversation)
- IChatClientProvider: Abstraction for obtaining an
IChatClient (from Microsoft.Extensions.AI) — a default implementation (InjectedChatClientProvider) resolves IChatClient from DI; custom implementations handle authentication, token management, and client construction
- IMessageStore: Abstraction for persisting and querying chat message history — implementations provide storage (SQLite, file system, cloud, etc.)
- ChatLookupAITool: AI tool that allows the AI to search past conversations via IMessageStore — automatically added by
ContextProvider when an IMessageStore is registered
- VoiceSelectionContextProvider: Optional
IContextProvider that adds three AI tools — get_available_voices, play_voice_sample, and change_voice — enabling the AI to list voices, play audio samples, and change its own TTS voice mid-conversation. Enabled via opts.AddVoiceSelectionTools().
- AiChatMessage: Record representing a persisted chat message with Id, Message, Timestamp, and Direction (User/AI)
- IContextProvider: Visitor-pattern abstraction for populating an
AiContext per request. Each provider's Apply(AiContext) method receives a mutable context and adds its contributions. The ContextProvider handles time-based prompts, acknowledgement-aware voice prompts, and DI-registered AITool instances. Implement custom providers to add domain-specific system prompts, tools, or override speech settings.
- AiContext: Mutable context object passed to
IContextProvider.Apply() — contains Acknowledgement, SystemPrompts, Tools, QuietWords, SpeechToTextOptions, and TextToSpeechOptions that providers populate or modify
- AiConversationOptions: Fluent configuration for DI registration — sets chat client provider, message store, sound provider, and additional context providers via
AddContextProvider<T>()
Built-in Provider Packages:
- Shiny.AiConversation.OpenAi (
OpenAiStaticChatProvider): Static OpenAI-compatible provider. Accepts API key, endpoint URI, and model name. Works with OpenAI, Azure OpenAI, Ollama, or any OpenAI-compatible API. Register with opts.AddStaticOpenAIChatClient(apiToken, endpointUri, modelName).
- Shiny.AiConversation.Maui.GithubCopilot (
GitHubCopilotChatClientProvider): MAUI-specific provider using GitHub device code OAuth flow and the Copilot API. Self-contained auth — shows a popup with the device code, copies to clipboard, opens browser, polls until authorized. Tokens stored in SecureStorage. Register with opts.AddGithubCopilotChatClient(). Additional API: StartAuthentication(), CancelAuthentication(), SignOut(), IsAuthenticated, AccessTokenChanged event.
Dependencies
Microsoft.Extensions.AI — IChatClient, ChatMessage, ChatRole, AITool, ChatOptions
Shiny.Speech — ISpeechToTextService, ITextToSpeechService, IAudioPlayer for voice interactions and sound effects
When to Use This Skill
Invoke this skill when the user wants to:
- Set up an AI chat service in a .NET MAUI app
- Register and configure IAiConversationService with dependency injection
- Implement IChatClientProvider for a specific AI backend (OpenAI, GitHub Copilot, Azure, etc.)
- Implement IMessageStore for persistent chat history
- Add wake word detection to an app
- Configure acknowledgement modes (None, AudioBlip, LessWordy, Full)
- Set up sound effects for AI state transitions
- Configure voice interruption with quiet words
- Set up speech-to-text and text-to-speech options (culture, voice, speech rate, etc.)
- Add the optional ChatLookupAITool for AI-driven history search
- Enable voice selection tools so the AI can list voices, play samples, and switch its own voice
- Build a chat UI that integrates with IAiConversationService
- Handle AI state changes (Idle, Listening, Thinking, Responding)
- Use TalkTo or ListenAndTalk for AI interactions
- Check speech/microphone access before starting voice features
Code Generation Instructions
1. Registration (MauiProgram.cs)
Always register with AddShinyAiConversation():
using Shiny.AiConversation;
builder.Services.AddChatClient(new OpenAIClient("your-api-key").GetChatClient("gpt-4o").AsIChatClient());
builder.Services.AddShinyAiConversation(opts =>
{
opts.AddStaticOpenAIChatClient("your-api-key", "https://api.openai.com/v1", "gpt-4o");
opts.AddGithubCopilotChatClient();
opts.SetMessageStore<MyMessageStore>();
});
- Built-in providers:
AddStaticOpenAIChatClient() for OpenAI-compatible APIs, AddGithubCopilotChatClient() for GitHub Copilot on MAUI
SetChatClientProvider<T>() is for custom providers — if not set and no built-in provider is used, the default InjectedChatClientProvider resolves IChatClient from DI
SetMessageStore<T>() is optional — enables persistent history; the ContextProvider automatically adds ChatLookupAITool when a store is present
AddVoiceSelectionTools() is optional — registers VoiceSelectionContextProvider, giving the AI tools to list voices, play samples, and change its own voice
AddContextProvider<T>() registers additional IContextProvider implementations
SetSoundProvider<T>() registers a custom ISoundProvider implementation
- System prompts, tools, quiet words, and speech options are provided via
IContextProvider implementations registered in DI (a ContextProvider is auto-registered)
2. Chat Client Setup
Simple approach — register IChatClient in DI (the default provider resolves it automatically):
builder.Services.AddChatClient(new OpenAIClient("your-api-key").GetChatClient("gpt-4o").AsIChatClient());
Advanced approach — implement IChatClientProvider for on-demand auth or token refresh:
public class MyChatClientProvider : IChatClientProvider
{
public async Task<IChatClient> GetChatClient(CancellationToken cancelToken = default)
{
return new OpenAIChatClient(...);
}
}
- Handle token expiry and re-authentication inside GetChatClient
- Can inject INavigator to navigate to a login page if authentication is needed on-demand
3. Implementing IContextProvider (Custom)
The ContextProvider is registered automatically and provides time-based prompts, acknowledgement-aware voice prompts, and any AITool instances from DI. To add custom system prompts, tools, or modify speech settings, implement IContextProvider using the visitor pattern and register it:
public class MyContextProvider : IContextProvider
{
public Task Apply(AiContext context)
{
context.SystemPrompts.Add("You are a helpful assistant for our company.");
return Task.CompletedTask;
}
}
builder.Services.AddShinyAiConversation(opts =>
{
opts.AddContextProvider<MyContextProvider>();
});
4. Implementing IMessageStore
public class MyMessageStore : IMessageStore
{
public Task Store(string? userTriggeringMessage, ChatResponse response, CancellationToken cancellationToken) { ... }
public Task Clear(DateTimeOffset? beforeDate = null) { ... }
public Task<IReadOnlyList<AiChatMessage>> Query(
string? messageContains = null,
DateTimeOffset? fromDate = null,
DateTimeOffset? toDate = null,
int? limit = null,
CancellationToken cancellationToken = default) { ... }
}
5. Using IAiConversationService
var access = await aiService.RequestAccess();
if (access != AccessState.Available)
{
return;
}
await aiService.TalkTo("What's the weather?", cancellationToken);
await aiService.ListenAndTalk(cancellationToken);
await aiService.StartWakeWord("Hey Assistant");
aiService.StopWakeWord();
var history = await aiService.GetChatHistory(limit: 25);
var filtered = await aiService.GetChatHistory(messageContains: "weather", startDate: yesterday);
await aiService.ClearChatHistory();
await aiService.ClearChatHistory(beforeDate: oneWeekAgo);
aiService.StatusChanged += (state) => { };
aiService.AiResponded += (response) =>
{
};
6. Acknowledgement Modes
| Mode | Behavior |
|---|
None | No audio feedback or TTS |
AudioBlip | Short sound effects at state transitions |
LessWordy | TTS with "be concise" system prompt injected |
Full | TTS with full unmodified responses |
7. AI States
| State | Description |
|---|
Idle | Ready for input |
Listening | Actively listening for speech |
Thinking | Waiting for AI to process |
Responding | AI is streaming its response |
Best Practices
- Use IContextProvider for configuration — System prompts, tools, quiet words, and speech options are all configured via
IContextProvider.Apply(AiContext) — not set directly on the service
- Handle auth on-demand — IChatClientProvider should handle authentication lazily, not force login at startup
- Use TwoWay binding for Acknowledgement in settings UIs
- Subscribe/unsubscribe to StatusChanged and AiResponded in page lifecycle (OnAppearing/OnDisappearing)
- Use CancellationToken for all TalkTo/ListenAndTalk calls
- MessageStore is optional — The service works without it but GetChatHistory/ClearChatHistory will throw
- ChatLookupAITool is opt-in — Pass
addAiLookupTool: true to SetMessageStore to allow the AI to search past conversations
- No reflection — All registrations must be explicit; do not use ActivatorUtilities.CreateInstance or reflection-based patterns