Blazor.AI.BrowserModels
0.1.0-preview.1
dotnet add package Blazor.AI.BrowserModels --version 0.1.0-preview.1
NuGet\Install-Package Blazor.AI.BrowserModels -Version 0.1.0-preview.1
<PackageReference Include="Blazor.AI.BrowserModels" Version="0.1.0-preview.1" />
<PackageVersion Include="Blazor.AI.BrowserModels" Version="0.1.0-preview.1" />
<PackageReference Include="Blazor.AI.BrowserModels" />
paket add Blazor.AI.BrowserModels --version 0.1.0-preview.1
#r "nuget: Blazor.AI.BrowserModels, 0.1.0-preview.1"
#:package Blazor.AI.BrowserModels@0.1.0-preview.1
#addin nuget:?package=Blazor.AI.BrowserModels&version=0.1.0-preview.1&prerelease
#tool nuget:?package=Blazor.AI.BrowserModels&version=0.1.0-preview.1&prerelease
Blazor.AI.BrowserModels
Blazor.AI.BrowserModels connects Blazor applications to language models exposed by the browser's Prompt API. Its primary API is BrowserModelChatClient, an implementation of Microsoft.Extensions.AI.IChatClient supporting completed and streamed text, structured JSON, and browser-owned image input.
Inference runs on the user's device. No API key, hosted model, database, or server-side inference service is required.
This is a preview package targeting .NET 10 and .NET 11. Browser support also depends on the installed model, hardware, storage, browser policy, and the page being served from localhost or HTTPS. See Chrome's Prompt API documentation for current requirements.
Install
dotnet add package Blazor.AI.BrowserModels --version 0.1.0-preview.1
The package includes its browser modules as static web assets; consumers do not need Node.js or a separate JavaScript build.
Use BrowserModelChatClient
Initialize a stateless browser session from a user gesture and keep the component mounted while the client is in use:
@using Blazor.AI.BrowserModels
@using Microsoft.Extensions.AI
<BrowserModelButton SessionMode="BrowserModelSessionMode.Stateless"
OnReady="ModelReady"
OnError="ModelFailed" />
@code {
private BrowserModelChatClient? chatClient;
private string? error;
private void ModelReady(BrowserModelSession session)
=> chatClient = new BrowserModelChatClient(session);
private void ModelFailed(string message) => error = message;
private async Task<string> AskAsync(string prompt)
{
ChatResponse response = await chatClient!.GetResponseAsync(
[new ChatMessage(ChatRole.User, prompt)]);
return response.Text;
}
}
BrowserModelButton owns the browser session. Disposing BrowserModelChatClient releases only the adapter; removing the button releases the model session.
Streaming
await foreach (ChatResponseUpdate update in chatClient.GetStreamingResponseAsync(
[new ChatMessage(ChatRole.User, "Explain local inference briefly.")],
cancellationToken: cancellationToken))
{
Console.Write(update.Text);
}
Streaming uses bounded batches and backpressure. Dispose an enumerator when stopping early so its browser reader and cloned model session are released promptly.
Structured output
var options = new ChatOptions
{
ResponseFormat = ChatResponseFormat.ForJsonSchema<Summary>()
};
ChatResponse response = await chatClient.GetResponseAsync(
[new ChatMessage(ChatRole.User, "Summarize this release.")], options);
public sealed record Summary(string Title, string[] KeyPoints);
The browser receives the JSON schema as its response constraint. The client validates returned JSON syntax; callers remain responsible for deserializing and validating application-specific requirements.
Images
Enable image input and place the attachment component around the prompt editor:
<BrowserModelButton SessionMode="BrowserModelSessionMode.Stateless"
EnableImages="true" OnReady="ModelReady" />
<BrowserModelAttachments @ref="attachments" Session="session">
<textarea @bind="prompt"></textarea>
</BrowserModelAttachments>
Capture the browser-owned selection and add it to a user message:
BrowserModelImageReference? images = await session.RetainImagesAsync(attachments);
var message = new ChatMessage(ChatRole.User, "Describe these images.");
if (images is not null)
message.Contents.Add(new BrowserModelImageContent(images));
ChatResponse response = await chatClient.GetResponseAsync([message]);
PNG, JPEG, and WebP files remain in the browser; their bytes are not copied through .NET interop. A selection accepts up to four files of 10 MiB each, and a model session retains at most 16 files or 64 MiB. Call ClearImagesAsync when resetting the corresponding chat history.
Microsoft Agent Framework
Applications using Microsoft.Agents.AI can adapt the same client:
var agent = chatClient.AsAIAgent(instructions: "Be helpful and concise.");
var conversation = await agent.CreateSessionAsync();
var reply = await agent.RunAsync("Hello", conversation);
Samples
Run the standalone WebAssembly sample:
dotnet run --project src/Blazor.AI.BrowserModels.Wasm --urls http://localhost:5188
Or run the Interactive Server sample:
dotnet run --project src/Blazor.AI.BrowserModels.Sample
Open the displayed localhost URL in a compatible desktop Chrome installation and initialize the model. The WebAssembly sample includes completed and streaming chat, structured responses, image input, and Agent Framework scenarios.
Runtime constraints
- Generation requires the owning page and browser connection to remain alive. Closing, reloading, freezing, or losing the circuit can interrupt a request; requests cannot resume in the background.
- Stateless chat replays the supplied history into one short-lived clone per request. Long histories increase model CPU work, context usage, and Blazor transport traffic.
- Only one request may use a browser session at a time. Unsupported roles, content, tools, per-request sampling, background responses, and continuation tokens fail before inference.
- Cancellation is request-scoped and best effort when the page is suspended. A browser-side two-minute timeout protects active pages.
- Image references belong to their original live session and must not be serialized or reused across reloads.
- In Interactive Server apps, text messages and replies cross the Blazor connection. Image bytes stay browser-local. The library does not persist or explicitly log prompts.
Build and test
The repository pins its preview .NET 11 SDK in global.json. Install both the .NET 10 and .NET 11 SDKs to build and run the complete unit-test matrix. Node.js 22.12 or newer is needed only when changing the TypeScript sources.
npm ci
npm run typecheck
npm test
npm run build
dotnet build Blazor.AI.BrowserModels.slnx -c Release
dotnet test tests/Blazor.AI.BrowserModels.Tests -c Release --no-build
dotnet test tests/Blazor.AI.BrowserModels.Playwright.Tests -c Release --no-build --filter 'Category!=RealModel'
dotnet pack src/Blazor.AI.BrowserModels -c Release --no-build -o artifacts/packages
Generated modules under src/Blazor.AI.BrowserModels/wwwroot are committed so package consumers do not require a JavaScript toolchain. The Playwright test guide documents deterministic browser tests and optional real-model checks.
License
| 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. net11.0 is compatible. |
-
net10.0
- Microsoft.AspNetCore.Components.Web (>= 10.0.11)
- Microsoft.Extensions.AI.Abstractions (>= 10.9.0)
-
net11.0
- Microsoft.AspNetCore.Components.Web (>= 11.0.0-rc.1.26425.128)
- Microsoft.Extensions.AI.Abstractions (>= 10.9.0)
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 |
|---|---|---|
| 0.1.0-preview.1 | 109 | 9/15/2026 |