Sample: Foundry Local + .NET MAUI on-device AI#749
Conversation
Sample guide showing how to add on-device AI via Foundry Local alongside Microsoft Foundry (cloud) in the Telepathy .NET MAUI app. Features: - IChatClient provider swap via DI (cloud ↔ local at runtime) - Windows: native SDK with WinML acceleration - Mac Catalyst: CLI REST API discovery (no NuGet needed) - ThinkingTagStripperChatClient for models that emit <think> tags - Manual JSON extraction for reliable structured output - Settings toggle with download progress UX - Platform support matrix and offline fallback patterns Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jfversluis
left a comment
There was a problem hiding this comment.
Code Multi-Model Consensus (Sonnet 4.5, GPT-5.2, Opus 4.6)Review
**1. Mac Catalyst won't no NuGet package for FoundryLocalManager**compile
Code uses FoundryLocalManager under #if WINDOWS || MACCATALYST (lines ~176-197), but the csproj only adds Microsoft.AI.Foundry.Local.WinML conditioned on -windows. The guide says macOS needs "no NuGet package" yet the C# directly references types from Microsoft.AI.Foundry.Local. The Mac build will fail on unresolved types.
Fix: Either add a Mac Catalyst package reference, or split the code paths so MACCATALYST uses a CLI-based discovery approach instead of the managed API.
2. AddChatClient(async sp => ...) won't compile
The alternative DI registration example (line ~584) uses an async factory lambda. Standard .NET DI factory delegates are synchronous (Func<IServiceProvider, there is no Func<IServiceProvider, Task> overload.T>)
Fix: Remove this example (the recommended IChatClientService pattern already handles async init correctly), or show a sync factory with .GetAwaiter().GetResult().
3. Missing OpenAI NuGet package in csproj snippet
Code uses using OpenAI; and new OpenAIClient(...), but the csproj snippet (lines ~65-68) only lists Azure.AI.OpenAI, Microsoft.Extensions.AI, and Microsoft.Extensions.AI.OpenAI. Readers following the guide will get compile errors.
Fix: Add the OpenAI package to the csproj snippet.
4. Mismatched package versions
Microsoft.Extensions.AI is shown at 9.9.1 while Microsoft.Extensions.AI.OpenAI is at 9.4.4-preview. These packages should be version-aligned to avoid binding issues.
5. ProgressBar value range mismatch
DownloadProgress = p.PercentComplete; (line ~676) assigns a 100 value, but MAUI ProgressBar.Progress expects 0.1.0. The bar will appear full as soon as download reaches 1%.00
Fix: DownloadProgress = p.PercentComplete / 100.0;
6. JSON extraction regex fails on nested objects
The generic GetStructuredResponseAsync<T> helper (line ~951) uses (\{[\s\S]*?\}) (lazy quantifier), which matches from the first { to the nearest }. For any JSON with nested objects this produces invalid JSON.
Fix: Use a greedy match (\{[\s\S]*\}) or implement brace-balancing extraction.
**7. async void crash risk + lazy resolution**ConnectivityWatcher
The OnConnectivityChanged handler is async void with no try/catch. Unhandled exceptions will crash the app. Additionally, the singleton is registered but never explicitly resolved, so the constructor (which hooks the event) may never run.
Fix: Add try/catch in the handler, and ensure the watcher is resolved at startup.
Review generated with Claude Sonnet 4.5, GPT-5.2, and Claude Opus 4.6.
Summary
Guide and code samples showing how to integrate Foundry Local (on-device AI) into a .NET MAUI app alongside Microsoft Foundry (cloud), with a runtime toggle between providers.
What's included
Microsoft.AI.Foundry.Local.WinMLThinkingTagStripperChatClientmiddleware for models that emit<think>reasoning tagsTested end-to-end on
Related
/cc @mattleibow @jfversluis