[maui-labs docs] Document AI Extensions — Microsoft.Maui.AI.Attributes source-generated AI tool bindings
- Dominant language
- No language data
- Stars
- 282
- Forks
- 265
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 19
Description
## Source PR
**PR**: https://github.com/dotnet/maui-labs/pull/107
**Title**: Add AI Extensions — source-generated AI tool bindings
**Author**: jfversluis
**Merged**: 2026-05-15
---
## Summary of Changes
PR #107 introduces a brand-new experimental product: **AI Extensions** (`Microsoft.Maui.AI.Attributes`). This is a source-generator–based library that lets .NET MAUI (and plain .NET 10) developers annotate methods and property accessors with `[ExportAIFunction]` to expose them as `Microsoft.Extensions.AI` `AITool` instances — with full DI parameter binding, approval gates, and AOT-safe code gen.
**New NuGet packages shipped:**
| Package | Description |
|---------|-------------|
| `Microsoft.Maui.AI.Attributes` | Runtime attributes and `AIToolContext` base class |
| `Microsoft.Maui.AI.Attributes.Generators` | Roslyn source generator (ships as analyzer reference in the runtime package) |
**Key user-facing surface:**
- `[ExportAIFunction]` attribute — marks a method, property getter, or setter as an AI-callable tool. Accepts an optional explicit tool name and `ApprovalRequired = true` for approval-gated tools.
- `[AIToolSource(typeof(T))]` attribute on a `partial class : AIToolContext` — declares which types contribute tools. The generator emits a sealed `AIFunction` per annotated method at compile time.
- **Assembly-wide auto context** — if no partial class is declared, the generator emits `(AssemblyName)ToolContext` collecting all `[ExportAIFunction]` members in the project automatically.
- `[FromServices]` / `[FromKeyedServices]` parameter attributes — DI binding at compile time; parameters are excluded from the JSON schema.
- Static tool support — static methods with no DI dependencies generate tools that work without any `IServiceProvider`.
- Compile-time diagnostics: `MAUIAI002` (unsupported parameter type), `MAUIAI003` (empty tool source), `MAUIAI004` (unsupported method signature).
**Sample apps included:**
| Sample | Type | Demonstrates |
|--------|------|-------------|
| `AIExtensions.Sample.Hello` | Console | Minimal end-to-end; one DI service + one static service |
| `AIExtensions.Sample.DIParameters` | Console | All parameter binding shapes (`[FromServices]`, `[FromKeyedServices]`, records, `CancellationToken`) |
| `AIExtensions.Sample.Garden` | MAUI | Full MAUI chat app: navigation, cart-mode property tools, approval flow, DevFlow integration |
---
## Documentation Pages Affected
### New pages needed
- `docs/developer-tools/ai-extensions/index.md` — overview and landing page for the AI Extensions product
- `docs/developer-tools/ai-extensions/ai-attributes.md` — full how-to for `Microsoft.Maui.AI.Attributes`
### Existing pages to update
- `docs/developer-tools/index.md` — add AI Extensions to the product listing
- `docs/TOC.yml` — add AI Extensions section under `developer-tools`
---
## Suggested Changes
### 1. New file: `docs/developer-tools/ai-extensions/index.md`
```markdown
---
title: AI Extensions
description: Experimental AI integration packages for .NET MAUI, built on Microsoft.Extensions.AI abstractions.
ms.date: 05/15/2026
---
# AI Extensions (experimental)
AI Extensions are a set of experimental packages for integrating on-device and cloud AI into .NET MAUI applications, built on the [`Microsoft.Extensions.AI`]((learn.microsoft.com/redacted) abstractions.
> [!WARNING]
> These packages are experimental. APIs may change between releases.
## Packages
| Package | Description |
|---------|-------------|
| `Microsoft.Maui.AI.Attributes` | Source-generated AI tool contexts — `[ExportAIFunction]`, DI binding, AOT-safe |
## Installation
```dotnetcli
dotnet add package Microsoft.Maui.AI.Attributes
```
## Next steps
- [Source-generated AI tool bindings](ai-attributes.md)
```
---
### 2. New file: `docs/developer-tools/ai-extensions/ai-attributes.md`
This is the main how-to article. Key sections and content:
#### Introduction paragraph
> `Microsoft.Maui.AI.Attributes` is a Roslyn source generator that turns annotated C# methods and property accessors into `Microsoft.Extensions.AI` `AITool` instances at compile time. No runtime reflection on the invocation path; AOT-friendly.
#### Section: Annotate your methods
```csharp
using System.ComponentModel;
using Microsoft.Maui.AI.Attributes;
public class PlantCatalogService
{
[Description("Searches the plant catalog by name or category.")]
[ExportAIFunction("search_plants")]
public List(PlantInfo) SearchPlants(
[Description("Optional filter text")] string? query = null)
{
// ...
}
}
```
- `[ExportAIFunction]` marks a method, property getter, or setter as an AI-callable tool.
- `[ExportAIFunction("custom_name")]` overrides the default tool name (which is the method name).
- `[ExportAIFunction(ApprovalRequired = true)]` wraps the tool in an approval gate.
- `[Description]` on the method and parameters provides AI-visible documentation.
#### Section: Define a tool context
```csharp
[AIToolSource(typeof(PlantCatalogService))]
[AIToolSource(typeof(GardenService))]
public partial class GardenTools : AIToolContext { }
```
The source generator scans each `[AIToolSource]` type at compile time and emits a sealed `AIFunction` subclass per method, plus a `Default` singleton and a `Tools` property on the context.
#### Section: Use the assembly-wide auto context
If you skip the partial class, the generator emits an **assembly-wide context** collecting every `[ExportAIFunction]` in the project:
```csharp
// For an assembly named "MyApp":
IReadOnlyList(AITool) tools = MyAppToolContext.Default.Tools;
```
The generated class name is `(AssemblyName)ToolContext` in the root namespace, with dots removed.
#### Section: Wire tools into an IChatClient
```csharp
var tools = GardenTools.Default.Tools;
var client = innerChatClient.AsBuilder()
.UseFunctionInvocation()
.ConfigureOptions(opts =>
{
opts.Tools ??= [];
foreach (var tool in tools)
opts.Tools.Add(tool);
})
.Build(serviceProvider);
await foreach (var update in client.GetStreamingResponseAsync(messages))
Console.Write(update.Text);
```
#### Section: Static tools (no DI required)
If a method is `static` and doesn't use `[FromServices]`, the generator emits a DI-free tool:
```csharp
public static class GreetingService
{
[Description("Returns a greeting for the given name.")]
[ExportAIFunction("say_hello")]
public static string SayHello(string name) => $"Hello, {name}!";
}
[AIToolSource(typeof(GreetingService))]
public partial class GreetingTools : AIToolContext { }
```
#### Section: DI parameter binding
At compile time the generator classifies parameters:
| Parameter shape | Binding | In schema? |
|----------------|---------|------------|
| `CancellationToken` | Injected from the invocation pipeline | No |
| `IServiceProvider` | From `AIFunctionArguments.Services` | No |
| `AIFunctionArguments` | The raw argument bag | No |
| `[FromServices] IMyThing x` | `provider.GetService(IMyThing)()` | No |
| `[FromKeyedServices("k")] IMyThing x` | Keyed service lookup | No |
| Everything else | Bound from JSON arguments | Yes |
#### Section: Property accessors
```csharp
public partial class CartViewModel
{
public string CartMode
{
[ExportAIFunction("get_cart_mode")]
[Description("Gets the current cart display mode.")]
get;
[ExportAIFunction("set_cart_mode")]
[Description("Sets the cart display mode. Valid values: 'normal', 'compact'.")]
set;
} = "normal";
}
```
Property getter tools have no JSON inputs. Setter tools emit a required `value` parameter.
#### Section: Approval-required tools
```csharp
[ExportAIFunction("delete_order", ApprovalRequired = true)]
[Description("Permanently deletes an order. Requires user approval.")]
public async Task DeleteOrderAsync(int orderId) { ... }
```
The generated tool wraps the invocation in an approval gate. Implement `AIToolContext.RequestApprovalAsync` to show a native confirmation UI.
#### Section: Key types reference table
| Type | Description |
|------|-------------|
| `ExportAIFunctionAttribute` | Marks a method/accessor as an AI tool |
| `AIToolSourceAttribute` | Declares which type contributes tools to a context |
| `AIToolContext` | Base class for source-generated contexts; exposes `Tools` and `Default` |
| `FromServicesAttribute` | Resolves a parameter from `IServiceProvider` |
#### Section: Compiler diagnostics
| ID | Severity | Meaning |
|----|----------|---------|
| `MAUIAI002` | Warning | Parameter type is unlikely to round-trip through JSON. Use `[FromServices]` or change the signature. |
| `MAUIAI003` | Warning | `[AIToolSource(typeof(T))]` references a type with no `[ExportAIFunction]` methods. |
| `MAUIAI004` | Error | Unsupported signature: generic method, `ref`/`out` parameters, etc. |
#### Section: AOT compatibility
The hot invocation path contains no reflection. Each tool is a compile-time-emitted `AIFunction` subclass. Schema generation uses `AIJsonUtilities.CreateFunctionJsonSchema` (reflective, invoked once per tool at warmup and cached).
---
### 3. Update: `docs/developer-tools/index.md`
In the product listing table, add a new row (after the existing DevFlow row or in a new "AI" section):
```markdown
| AI Extensions | [Microsoft.Maui.AI.Attributes](ai-extensions/index.md) | Source-generated AI tool bindings for Microsoft.Extensions.AI |
```
---
### 4. Update: `docs/TOC.yml`
Under the `developer-tools` node, add:
```yaml
- name: AI Extensions
items:
- name: Overview
href: ai-extensions/index.md
- name: Source-generated AI tool bindings
href: ai-extensions/ai-attributes.md
```
---
## Additional Notes
- The product targets **net10.0** only (no MAUI TFMs required for the base package; the Garden sample is a full MAUI app).
- The package is experimental — all documentation pages should carry the `> [!WARNING] These packages are experimental.` callout.
- The Garden sample (`samples/AIExtensions.Sample.Garden`) demonstrates DevFlow integration alongside AI tools — worth linking from the DevFlow docs as a cross-reference.
- Source: `src/AIExtensions/Microsoft.Maui.AI.Attributes/README.md` in the maui-labs repo has the authoritative API reference and equivalence table vs `AIFunctionFactory`.
> Generated by [PR Documentation Check](https://github.com/dotnet/maui-labs/actions/runs/25920144786) for issue #107 · [◷](https://github.com/search?q=repo%3Adotnet%2Fdocs-maui+is%3Aissue+%22gh-aw-workflow-call-id%3A+dotnet%2Fmaui-labs%2Fpr-docs-check%22&type=issues)
Contributor guide
Assessment
This issue has not been assessed yet.