dotnet / dotnet/docs-maui

[maui-labs docs] Document AI Extensions — Microsoft.Maui.AI.Attributes source-generated AI tool bindings

Open
#3,340 0 comments 0 reactions 0 assignees View on GitHub
:watch: Not Triaged Pri3
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.