Shiny.AiConversation.GithubCopilot
3.0.0-beta-0022
Prefix Reserved
See the version list below for details.
dotnet add package Shiny.AiConversation.GithubCopilot --version 3.0.0-beta-0022
NuGet\Install-Package Shiny.AiConversation.GithubCopilot -Version 3.0.0-beta-0022
<PackageReference Include="Shiny.AiConversation.GithubCopilot" Version="3.0.0-beta-0022" />
<PackageVersion Include="Shiny.AiConversation.GithubCopilot" Version="3.0.0-beta-0022" />
<PackageReference Include="Shiny.AiConversation.GithubCopilot" />
paket add Shiny.AiConversation.GithubCopilot --version 3.0.0-beta-0022
#r "nuget: Shiny.AiConversation.GithubCopilot, 3.0.0-beta-0022"
#:package Shiny.AiConversation.GithubCopilot@3.0.0-beta-0022
#addin nuget:?package=Shiny.AiConversation.GithubCopilot&version=3.0.0-beta-0022&prerelease
#tool nuget:?package=Shiny.AiConversation.GithubCopilot&version=3.0.0-beta-0022&prerelease
Shiny.AiConversation
A centralized AI service library for .NET MAUI apps that orchestrates chat, speech recognition, wake word detection, text-to-speech, and persistent message history into a single IAiConversationService interface.
Features
- Chat Integration — Send text or voice messages to any AI backend via Microsoft.Extensions.AI
- Wake Word Detection — Hands-free activation with continuous keyword listening
- Speech-to-Text / Text-to-Speech — Full voice loop powered by Shiny.Speech
- Acknowledgement Modes — None, AudioBlip (sound effects), LessWordy (concise TTS), or Full (complete TTS)
- Context Providers — Pluggable
IContextProvidervisitor pattern for populating anAiContextper request. Each provider receives a mutable context containing system prompts, AI tools, quiet words, speech-to-text options, and text-to-speech options. A built-inContextProviderhandles time-based prompts, acknowledgement-aware voice prompts, and DI-registeredAIToolinstances. - Persistent Chat History — Pluggable
IMessageStorefor storing and querying past conversations - AI History Lookup Tool — Automatically available when an
IMessageStoreis registered, lets the AI search past conversations on its own - Voice Selection Tools — Optional
AddVoiceSelectionTools()enables the AI to list voices, play samples, and switch its own TTS voice mid-conversation - State Management — Observable
AiState(Idle / Listening / Thinking / Responding) with events - Sound Effects — Configurable sound stream factories for each state transition
- Conversation Continuation — AI responses ending with a question automatically keep the microphone open for a reply
- Voice Interruption — Configurable quiet words (e.g., "stop", "cancel") via
AiContext.QuietWordsimmediately silence TTS and break out of the conversation. Any other speech during TTS interrupts and continues the conversation with the new utterance. - Speech Options — Configurable
SpeechToTextOptionsandTextToSpeechOptionsviaAiContext(culture, silence timeout, voice, speech rate, etc.)
TODO
- Sessions - ability to start different AI sessions based on time passed
- Acknowledgement sounds is present, but we need acknowledgement "Hi User" or "What can I help you with?"
- Manually activation could just be a sound? Maybe only the wake word should have a greeting, and manual text input doesn't need it?
- Speech to text - Wait for anything? then 2 seconds of silence
Installation
dotnet add package Shiny.AiConversation
Quick Start
1. Register the service
using Shiny.AiConversation;
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts => { ... });
// Register an IChatClient in DI (from any Microsoft.Extensions.AI-compatible provider)
builder.Services.AddChatClient(new OpenAIClient("your-api-key").GetChatClient("gpt-4o").AsIChatClient());
builder.Services.AddShinyAiConversation(opts =>
{
// Optional — enable persistent history (ChatLookupAITool is added automatically)
opts.SetMessageStore<MyMessageStore>();
});
return builder.Build();
2. Chat Client Setup
By default, the library resolves IChatClient from DI. Simply register your chat client with the container:
builder.Services.AddChatClient(new OpenAIClient("your-api-key").GetChatClient("gpt-4o").AsIChatClient());
Shiny.AiConversation.OpenAi
A ready-made static OpenAI provider. Works with any OpenAI-compatible endpoint (OpenAI, Azure OpenAI, Ollama, etc.).
dotnet add package Shiny.AiConversation.OpenAi
builder.Services.AddShinyAiConversation(opts =>
{
opts.AddStaticOpenAIChatClient(
apiToken: "your-api-key",
endpointUri: "https://api.openai.com/v1",
modelName: "gpt-4o"
);
});
Shiny.AiConversation.Maui.GithubCopilot
A MAUI-specific provider that authenticates via the GitHub device code flow and uses the Copilot API. Tokens are stored in SecureStorage. Authentication is fully self-contained — the library shows a popup with the device code, copies it to the clipboard, and opens the browser for the user to authorize.
dotnet add package Shiny.AiConversation.Maui.GithubCopilot
builder.Services.AddShinyAiConversation(opts =>
{
opts.AddGithubCopilotChatClient();
});
No additional setup is needed — the provider handles the entire OAuth flow, token exchange, caching, and re-authentication on expiry.
Custom Provider
For other backends, implement IChatClientProvider:
using Microsoft.Extensions.AI;
using Shiny.AiConversation;
public class MyChatClientProvider : IChatClientProvider
{
public async Task<IChatClient> GetChatClient(CancellationToken cancelToken = default)
{
// Handle auth, token refresh, etc.
return BuildChatClient();
}
}
// Register it:
builder.Services.AddShinyAiConversation(opts =>
{
opts.SetChatClientProvider<MyChatClientProvider>();
});
3. Implement IMessageStore (optional)
Provide persistent storage for chat history. Without this, GetChatHistory and ClearChatHistory will throw.
using Shiny.AiConversation;
public class MyMessageStore : IMessageStore
{
public Task Store(string? userTriggeringMessage, ChatResponse response, CancellationToken cancellationToken)
{
// Persist the complete AI response
}
public Task Clear(DateTimeOffset? beforeDate = null)
{
// Clear all or messages before the given date
}
public Task<IReadOnlyList<AiChatMessage>> Query(
string? messageContains = null,
DateTimeOffset? fromDate = null,
DateTimeOffset? toDate = null,
int? limit = null,
CancellationToken cancellationToken = default)
{
// Query with optional filters, return ordered by timestamp
}
}
4. Use the service
public class ChatViewModel(IAiConversationService aiService) : ObservableObject
{
public async Task SendMessage(string text)
{
await aiService.TalkTo(text, CancellationToken.None);
}
public async Task UseMicrophone()
{
var access = await aiService.RequestAccess();
if (access != AccessState.Available)
return;
await aiService.ListenAndTalk(CancellationToken.None);
}
public async Task StartWakeWord()
{
await aiService.StartWakeWord("Hey Assistant");
}
}
MAUI Chat UI
Shiny.AiConversation.Maui ships AiChatView — a chat screen already wired to
IAiConversationService. It derives from the Shiny.Maui.Controls
ChatView, so every style, template and behavior property of the base control still applies, while
sends, AI replies, voice turns, the typing indicator and message-store history are handled for you.
dotnet add package Shiny.AiConversation.Maui
<ContentPage xmlns:ai="http://shiny.net/maui/aiconversation">
<ai:AiChatView BotName="Aura"
BotAvatar="bot.png"
GreetingMessage="Hi! What can I help you with?"
ShowMicrophoneAction="True"
MyBubbleColor="{StaticResource Primary}"
OtherBubbleColor="#F0EEFF"
BubbleCornerRadius="16" />
</ContentPage>
See the documentation for the full property list.
API Overview
IAiConversationService
| Member | Description |
|---|---|
RequestAccess() |
Check speech-to-text access — returns Available or Restricted |
TalkTo(string, CancellationToken) |
Send a text message to the AI |
ListenAndTalk(CancellationToken) |
Capture speech via microphone and send to AI |
StartWakeWord(string) |
Begin continuous wake word detection |
StopWakeWord() |
Stop wake word detection |
GetChatHistory(...) |
Query persisted chat history with optional filters |
ClearChatHistory(...) |
Clear persisted history (all or before a date) |
ClearCurrentChat() |
Clear in-memory session messages |
Status |
Current AiState (Idle / Listening / Thinking / Responding) |
Acknowledgement |
Get/set the response delivery mode |
StatusChanged |
Event fired with the new AiState on any state change |
AiResponded |
Event fired when the AI completes a response with AiResponse (Response, WasReadAloud, ExpectsResponse) |
AiContext
The AiContext is a mutable context object populated by IContextProvider implementations before each AI request:
| Property | Description |
|---|---|
Acknowledgement |
The current acknowledgement mode (set by the service before providers run) |
SystemPrompts |
System prompt strings to include in the chat request |
Tools |
AI tools available for the request |
QuietWords |
Words that stop TTS and break the conversation loop (default: cancel, quiet, shut up, stop, nevermind, never mind, hush) |
SpeechToTextOptions |
Options for speech-to-text (culture, silence timeout, prefer on-device) |
TextToSpeechOptions |
Options for text-to-speech (culture, voice, speech rate, pitch, volume) |
Acknowledgement Modes
| Mode | Behavior |
|---|---|
None |
No audio feedback or text-to-speech |
AudioBlip |
Short sound effects at state transitions |
LessWordy |
Text-to-speech with a "be concise" system prompt |
Full |
Text-to-speech with full unmodified responses |
ChatLookupAITool
When an IMessageStore is registered via SetMessageStore<T>(), the built-in ContextProvider automatically adds a ChatLookupAITool (lookup_chat_history) to every request. This allows the AI to autonomously search past conversations when the user asks about previous discussions — no extra code required.
VoiceSelectionTools (optional)
Call AddVoiceSelectionTools() during registration to give the AI three voice-related tools:
| Tool | Description |
|---|---|
get_available_voices |
Lists all available TTS voices, optionally filtered by culture code |
play_voice_sample |
Speaks a sample phrase using a specific voice so the user can hear it |
change_voice |
Switches the AI's speaking voice; persists for the session |
builder.Services.AddShinyAiConversation(opts =>
{
opts.AddStaticOpenAIChatClient(...);
opts.AddVoiceSelectionTools();
});
Once registered, the user can say things like:
- "Can you play a few different voices for me?"
- "Switch to a different voice"
- "Use a British accent"
The selected voice is written directly to IAiConversationService.TextToSpeechOptions, which the service uses for all subsequent TTS responses. Requires ITextToSpeechService — available automatically when AutoAddSpeechServices is true (the default).
Architecture
┌─────────────────────────────────────────────────┐
│ IAiConversationService │
│ (orchestrates chat, speech, sounds, history) │
├──────────┬──────────────┬───────────────────────┤
│ │ │ │
│ IChatClientProvider │ IMessageStore │
│ (default: resolves │ (persistence) │
│ IChatClient from DI) │ │
│ │ │ │ │
│ IChatClient ISpeechToText │ ChatLookupAITool
│ (M.E.AI) ITextToSpeech │ (optional AITool)
│ (Shiny.Speech) │ │
│ │ │ │
│ IAudioPlayer │ │
│ (Shiny.Speech) │ │
└─────────────────────────────────────────────────┘
Dependencies
| Package | Purpose |
|---|---|
| Microsoft.Extensions.AI | IChatClient abstraction |
| Shiny.Speech | Speech-to-text, text-to-speech, and audio playback |
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.AI.OpenAI (>= 10.7.0)
- Shiny.AiConversation (>= 3.0.0-beta-0022)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-beta-0024 | 0 | 8/5/2026 |
| 3.0.0-beta-0023 | 0 | 8/5/2026 |
| 3.0.0-beta-0022 | 47 | 8/2/2026 |
| 3.0.0-beta-0021 | 39 | 7/31/2026 |
| 3.0.0-beta-0020 | 41 | 7/30/2026 |
| 3.0.0-beta-0019 | 41 | 7/30/2026 |
| 3.0.0-beta-0018 | 42 | 7/27/2026 |
| 3.0.0-beta-0017 | 48 | 7/26/2026 |
| 3.0.0-beta-0016 | 46 | 7/24/2026 |
| 3.0.0-beta-0015 | 46 | 7/23/2026 |
| 3.0.0-beta-0014 | 53 | 7/11/2026 |
| 3.0.0-beta-0013 | 58 | 7/10/2026 |
| 3.0.0-beta-0012 | 45 | 7/9/2026 |
| 3.0.0-beta-0011 | 50 | 7/9/2026 |
| 3.0.0-beta-0009 | 53 | 7/8/2026 |
| 3.0.0-beta-0008 | 60 | 7/8/2026 |
| 3.0.0-beta-0007 | 55 | 7/7/2026 |
| 3.0.0-beta-0006 | 49 | 7/7/2026 |
| 3.0.0-beta-0005 | 55 | 7/7/2026 |
| 3.0.0-beta-0004 | 56 | 7/6/2026 |