Skip to content
Shiny.Maui.Shell v6 support for AI routing tools Learn More

Shell | AI Integration

Shiny Shell’s source generation can produce metadata and navigation methods designed for AI tool calling via Microsoft.Extensions.AI. An AI chat client can discover your app’s routes, understand their purpose, extract parameters from natural language, and navigate to the correct page — all with generated AITool instances.

  1. Install the Microsoft.Extensions.AI NuGet package:
Terminal window
dotnet add package Microsoft.Extensions.AI
  1. Enable AI extensions in your .csproj:
<PropertyGroup>
<ShinyMauiShell_GenerateAiExtensions>true</ShinyMauiShell_GenerateAiExtensions>
</PropertyGroup>

The AI integration builds on the same [ShellMap] and [ShellProperty] attributes you already use. Add description parameters that explain user intent rather than just naming the page, and the source generator produces everything the AI needs.

The flow:

  1. AI calls GetAiToolApplicableGeneratedRoutes() to discover what pages exist and what they do
  2. AI matches user intent to the right route based on descriptions
  3. AI extracts parameter values from natural language
  4. AI calls NavigateToRoute() with the route and parameters
  5. The app navigates and the form is pre-populated

The description parameter on [ShellMap] tells the AI when to use this route. Write it as intent signals, not page names:

// Good — describes user intent
[ShellMap<WorkOrderPage>(description: "Use when the user reports something broken, malfunctioning, needing repair, or any physical problem that needs to be fixed")]
// Bad — just names the page
[ShellMap<WorkOrderPage>(description: "Work order page")]

The description parameter on [ShellProperty] tells the AI how to infer the value from what the user said:

// Good — tells AI to extract and infer
[ShellProperty("Summarize what is broken based on what the user said", required: true)]
public string Description { get; set; } = string.Empty;
[ShellProperty("Infer urgency from the user's tone. Must be: Low, Medium, High, or Urgent", required: true)]
public WorkOrderPriority Priority { get; set; } = WorkOrderPriority.Medium;
// Bad — just names the field
[ShellProperty("The description")]
public string Description { get; set; } = string.Empty;

NavigateToRoute accepts Dictionary<string, string> from the AI and automatically converts string values to the correct property type. The following types are supported:

TypeConversion
stringDirect assignment
int, long, short, byteT.Parse(value)
float, double, decimalT.Parse(value)
boolbool.Parse(value)
Guid, DateTime, DateTimeOffset, TimeSpanT.Parse(value)
Urinew Uri(value)
EnumsEnum.Parse(typeof(T), value, true) — case-insensitive
Other typesConvert.ChangeType fallback

Enums work especially well with AI — the model naturally outputs the enum member name as a string (e.g. "Urgent"), and the generator handles the parsing with case-insensitive matching.

public enum WorkOrderPriority { Low, Medium, High, Urgent }
[ShellMap<WorkOrderPage>(description: "Use when the user reports something broken, malfunctioning, needing repair, maintenance, or service")]
public partial class WorkOrderViewModel(INavigator navigator) : ObservableObject
{
[ShellProperty("Summarize what is broken based on what the user said", required: true)]
public string Description { get; set; } = string.Empty;
[ShellProperty("Infer urgency from the user's tone. Must be: Low, Medium, High, or Urgent", required: true)]
public WorkOrderPriority Priority { get; set; } = WorkOrderPriority.Medium;
[ShellProperty("The physical location if the user mentioned one, otherwise leave empty", required: false)]
public string Location { get; set; } = string.Empty;
}
## Generated AI Extensions
When AI extensions are enabled, the source generator produces the following members in `AiExtensions.g.cs`:
### GetAiToolApplicableGeneratedRoutes
Returns only routes that have a `description` on `[ShellMap]` **and** at least one `[ShellProperty]`. These are routes an AI can meaningfully discover and navigate to.
```csharp
[Description("This provides a list of AI tool applicable routes")]
public static GeneratedRouteInfo[] GetAiToolApplicableGeneratedRoutes(this INavigator navigator);

A pre-formatted string describing all AI-applicable routes, their descriptions, and parameters. Designed to be included in an AI system message so the model knows which routes are available without calling a discovery tool first.

public static string AiRoutePrompt(this INavigator navigator);

AI-friendly navigation that accepts Dictionary<string, string> and dispatches to NavigateTo<TViewModel> with direct property setters. String values are automatically converted to the target property type (see Supported Property Types). Returns a confirmation message string.

[Description("Navigate to a route in the application, passing parameters as key-value pairs. Returns a confirmation message.")]
public static Task<string> NavigateToRoute(
this INavigator navigator,
[Description("The route name to navigate to")] string route,
[Description("Route parameters as key-value pairs")] Dictionary<string, string>? args = null);

Returns ready-to-use AITool instances for route discovery and navigation. This is the recommended way to wire up AI tools — no manual AIFunctionFactory.Create calls needed.

public static IList<AITool> GetAiTools(this INavigator navigator);
namespace Shiny.Infrastructure;
public record GeneratedRouteInfo(
string Route, // Route name from [ShellMap]
string Description, // Description from [ShellMap] (empty if not provided)
GeneratedRouteParameter[] Parameters // All [ShellProperty] properties
);
public record GeneratedRouteParameter(
string ParameterName, // Property name — used as key in NavigateToRoute args
string Description, // From [ShellProperty("...")] — empty if not provided
string TypeName, // CLR type: "string", "int", "bool", etc.
bool IsRequired // From [ShellProperty(required: ...)]
);

Use the generated GetAiTools() method — it returns ready-to-use AITool instances:

using Microsoft.Extensions.AI;
var tools = navigator.GetAiTools();
var options = new ChatOptions { Tools = [.. tools] };
var response = await chatClient.GetResponseAsync(history, options);

You can also seed the AI with route info upfront via AiRoutePrompt, so the model knows what routes are available without making a discovery call first:

history.Add(new ChatMessage(ChatRole.System,
$"You are a helpful assistant. {navigator.AiRoutePrompt()}"));

The two-tool design (discover + navigate) scales to any number of routes without registering a separate tool per page. The AI:

  1. Calls GetRoutes (backed by GetAiToolApplicableGeneratedRoutes) to see all available pages, their descriptions, and parameter schemas
  2. Matches the user’s intent to the right route based on descriptions
  3. Calls NavigateToRoute with the extracted route name and parameters

This avoids registering a generated NavigateToWorkOrder(...) tool for every page — which doesn’t scale and pollutes the tool list.

GetAiToolApplicableGeneratedRoutes filters to routes that meet both criteria:

  • The [ShellMap] has a non-null description
  • The ViewModel has at least one [ShellProperty]

Routes like your home page or settings page that don’t need AI parameter filling are excluded automatically. This keeps the AI’s tool response focused on pages it can actually act on.

AI extensions are disabled by default and can be enabled or customized via MSBuild properties in your .csproj:

<PropertyGroup>
<!-- Enable AI extensions (disabled by default, requires Microsoft.Extensions.AI) -->
<ShinyMauiShell_GenerateAiExtensions>true</ShinyMauiShell_GenerateAiExtensions>
<!-- Customize the generated class name (default: AiExtensions) -->
<ShinyMauiShell_AiExtensionsClassName>MyAppRouteExtensions</ShinyMauiShell_AiExtensionsClassName>
<!-- Customize the AI navigate method name (default: NavigateToRoute) -->
<ShinyMauiShell_AiNavigateMethodName>GoToPage</ShinyMauiShell_AiNavigateMethodName>
</PropertyGroup>
PropertyDefaultControls
ShinyMauiShell_GenerateAiExtensionsfalseGetAiToolApplicableGeneratedRoutes, NavigateToRoute, GetAiTools(), and AiRoutePrompt. Requires Microsoft.Extensions.AI (SHINY003 error if missing)
ShinyMauiShell_AiExtensionsClassNameAiExtensionsClass name for the route info/AI extensions class
ShinyMauiShell_AiNavigateMethodNameNavigateToRouteMethod name for the AI-friendly navigate method
DoDon’t
Describe user intent signalsName the page
”Use when the user reports something broken""Work order form”
Tell AI to infer from contextExpect exact field values
”Infer urgency from tone""The priority level”
Make optional fields truly optionalRequire everything
”Leave empty if not mentioned”Require the user to state everything