Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .devcontainer/.net/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": ".NET Aspire",
// Base .NET 9 image. Alternatively a Dockerfile/compose could be used.
"image": "mcr.microsoft.com/devcontainers/dotnet:9.0-bookworm",
// Base .NET 10 image. Alternatively a Dockerfile/compose could be used.
"image": "mcr.microsoft.com/devcontainers/dotnet:10.0-bookworm",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:3": {},
"ghcr.io/devcontainers/features/powershell:2": {},
Expand Down
8 changes: 4 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build", // Name of your build task in tasks.json
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net9.0/BuildWithAspire.AppHost.dll",
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net10.0/BuildWithAspire.AppHost.dll",
"args": ["--environment", "Ollama"],
"cwd": "${workspaceFolder}/src/BuildWithAspire.AppHost",
"stopAtEntry": false,
Expand All @@ -23,7 +23,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build", // Name of your build task in tasks.json
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net9.0/BuildWithAspire.AppHost.dll",
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net10.0/BuildWithAspire.AppHost.dll",
"args": ["--environment", "GitHubModels"],
"cwd": "${workspaceFolder}/src/BuildWithAspire.AppHost",
"stopAtEntry": false,
Expand All @@ -34,7 +34,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build", // Name of your build task in tasks.json
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net9.0/BuildWithAspire.AppHost.dll",
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net10.0/BuildWithAspire.AppHost.dll",
"args": ["--environment", "FoundryLocal"],
"cwd": "${workspaceFolder}/src/BuildWithAspire.AppHost",
"stopAtEntry": false,
Expand All @@ -45,7 +45,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build", // Name of your build task in tasks.json
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net9.0/BuildWithAspire.AppHost.dll",
"program": "${workspaceFolder}/src/BuildWithAspire.AppHost/bin/Debug/net10.0/BuildWithAspire.AppHost.dll",
"args": ["--environment", "AzureOpenAI"],
"cwd": "${workspaceFolder}/src/BuildWithAspire.AppHost",
"stopAtEntry": false,
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Chat Agent WeatherTools

### Prerequisites

- .NET 9.0 SDK or later
- .NET 10.0 SDK or later
- Docker Desktop (for Aspire)
- Visual Studio Code or Visual Studio 2022

Expand Down
5 changes: 5 additions & 0 deletions aspire.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"appHost": {
"path": "src/BuildWithAspire.AppHost/BuildWithAspire.AppHost.csproj"
}
}
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.0",
"version": "10.0.0",
"rollForward": "latestMajor",
"allowPrerelease": false
}
Expand Down
12 changes: 12 additions & 0 deletions nuget.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="https://api.nuget.org/v3/index.json" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="https://api.nuget.org/v3/index.json">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>
79 changes: 45 additions & 34 deletions slides/Slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ footer: '@Chris_L_Ayers - https://chris-ayers.com'

- **Databases**: PostgreSQL, MySQL, MongoDB, SQL Server
- **Messaging**: Kafka, RabbitMQ, NATS
- **AI & Observability**: Ollama, Semantic Kernel, OpenTelemetry
- **AI & Observability**: Ollama, OpenAI, Foundry, OpenTelemetry

</div>
<div>
Expand Down Expand Up @@ -235,34 +235,34 @@ footer: '@Chris_L_Ayers - https://chris-ayers.com'
---


# What's New in .NET Aspire 9.5
# What's New in .NET Aspire 13.4

<div class="columns">
<div>

## ⚙️ CLI & Tooling

- **aspire update** - Auto-update packages
- **SSH Remote port forwarding** in VS Code
- **TypeScript AppHost** now GA
- **aspire deploy / publish** GA
- **AI agent readiness** via skills

## 🎨 Dashboard Enhancements
## 🎨 Dashboard

- **GenAI Visualizer** - Explore AI interactions
- **Multi-resource console** logs view
- **AI Agents dialog**
- Structured search & trace filtering

</div>
<div>

## 🤖 New Integrations
## 🧩 App Model

- **OpenAI hosting** integration
- **GitHub Models** & **Azure AI Foundry** catalogs
- **Dev Tunnels** hosting support
- **Go** & **Bun** hosting integrations
- **Blazor WebAssembly** hosting (preview)

## 🚀 Deployment

- **Azure Container App Jobs**
- **Built-in Azure deployment** via `aspire deploy`
- **Azure Container App Jobs** stable
- Richer **Kubernetes / AKS** APIs

</div>
</div>
Expand Down Expand Up @@ -324,7 +324,6 @@ aspire exec
```bash
azd up # Deploy everything
azd deploy # App only
azd provision # Infrastructure only
azd init # Initialize
```

Expand All @@ -336,9 +335,7 @@ azd init # Initialize
- Auto-detects app structure
- Environment variable mapping
- Native Aspire support
- Credential providers
- Key Vault integration
- Secure access

</div>
</div>
Expand Down Expand Up @@ -368,8 +365,6 @@ var api = builder.AddProject<Projects.Api>("api")
- **Automatic prompting** for missing parameters
- **Rich form inputs** in dashboard
- **Secret masking** for sensitive data
- **Validation support** with custom rules
- **Save to user secrets** for persistence

**Input Types**: Text, Password, Choice, Boolean, Number

Expand All @@ -383,7 +378,7 @@ var api = builder.AddProject<Projects.Api>("api")
| **Component** | **Local** | **Cloud** |
|--------------|----------|----------|
| **AI Models** | Ollama, Foundry local, LM Studio | Azure OpenAI, AI Foundry |
| **Models** | Llama 3, Phi-4, Qwen | GPT-4.1, GPT-5-mini, Claude 4 |
| **Models** | Llama 3.2, Qwen2.5, Phi-4 | GPT-5, GPT-5-mini, Claude 4 |
| **Vector DB** | Qdrant, Chroma, pgvector | Azure AI Search, Cosmos DB |

**Features**: Zero-friction transitions • Emulator support • Hybrid development • Auto configuration • Secret management
Expand Down Expand Up @@ -430,7 +425,6 @@ public class ExampleService(IChatClient chatClient)
- **Privacy & Security**: All data stays on your machine
- **Offline Capability**: Work without internet connectivity
- **Fast Iteration**: No network latency for testing
- **Model Experimentation**: Try different open-source models

</div>
</div>
Expand Down Expand Up @@ -461,11 +455,10 @@ public class ExampleService(IChatClient chatClient)
</div>
<div>

- **Latest Models**: Access to GPT-4, Claude, and cutting-edge AI
- **Latest Models**: Access to GPT-5, Claude 4, and cutting-edge AI
- **Global Availability**: 99.9% SLA with worldwide deployment
- **Managed Infrastructure**: No server maintenance required
- **Advanced Features**: Function calling, vision, audio processing
- **Compliance Ready**: SOC 2, HIPAA, and enterprise certifications

</div>
</div>
Expand All @@ -491,7 +484,6 @@ public class ExampleService(IChatClient chatClient)
- **Inconsistent APIs**: Each framework had unique approaches
- **Integration Complexity**: Difficult to combine tools
- **Provider Lock-in**: Hard to switch AI providers
- **Learning Curve**: Multiple frameworks to master

</div>
</div>
Expand All @@ -505,22 +497,43 @@ public class ExampleService(IChatClient chatClient)

## Unified Multi-Agent Platform

- **Consolidation**: Replaces Semantic Kernel & AutoGen
- **Built on Microsoft.Extensions.AI**: Leverages unified abstractions
- **Multi-Agent Orchestration**: Coordinate multiple AI agents
- **Event-Driven Architecture**: Flexible agent communication
- **Now GA**: Unifies Semantic Kernel & AutoGen
- **Built on Microsoft.Extensions.AI**: Unified abstractions
- **Multi-Agent Orchestration**: Coordinate AI agents

</div>
<div>

## Key Features

- **Agent Types**: Task-based, conversational, autonomous
- **Memory Systems**: Short-term and long-term context
- **Tool Integration**: Function calling and external tools
- **Tool Integration**: MCP tools & function calling
- **Provider Agnostic**: Works with any AI backend

**Learn more**: [Microsoft Agent Framework](https://github.com/microsoft/agent-framework)
</div>
</div>

---

# Model Context Protocol (MCP)

<div class="columns">
<div>

## Standardized Tool Access

- **Open protocol** for exposing tools to AI
- **Dynamic discovery**: agents load tools at runtime
- **Transport-agnostic**: stdio, HTTP, SSE

</div>
<div>

## In this Demo

- **MCP server** hosts Math, Weather, System & Text tools
- **MAF agent** discovers tools via `McpClientTool`
- **Local tool-calling** with Foundry Local (Qwen2.5)

</div>
</div>
Expand All @@ -547,19 +560,17 @@ public class ExampleService(IChatClient chatClient)
## Links

- [.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview)
- [What's new in .NET Aspire 9.5](https://learn.microsoft.com/en-us/dotnet/aspire/whats-new/dotnet-aspire-9.5)
- [What's new in .NET Aspire 13.4](https://aspire.dev/whats-new/aspire-13-4/)
- [Microsoft.Extensions.AI](https://learn.microsoft.com/en-us/dotnet/ai/microsoft-extensions-ai)
- [Microsoft Agent Framework](https://github.com/microsoft/agent-framework)
- [Aspirify](https://aspireify.net/)
- [Aspire Samples](https://github.com/dotnet/aspire-samples)
- [eShopLite](https://github.com/Azure-Samples/eShopLite)

</div>
<div>

## Follow Chris Ayers

![w:400px](./img/chris_ayers.svg)
![w:300px](./img/chris_ayers.svg)

<!--
<i class="fa-brands fa-bluesky"></i> BlueSky: [@chris-ayers.com](https://bsky.app/profile/chris-ayers.com)
Expand Down
30 changes: 25 additions & 5 deletions src/BuildWithAspire.Abstractions/AIConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ public enum AIProvider
AzureAIFoundry
}

public record AISettings(AIProvider Provider, string DeploymentName, string Model, int TimeoutSeconds);
public record AISettings(AIProvider Provider, string DeploymentName, string Model, int TimeoutSeconds)
{
/// <summary>
/// True when the model was set explicitly via <c>AI:Model</c> configuration,
/// as opposed to falling back to the provider default. The AppHost uses this to
/// choose between the strongly-typed model catalog (defaults) and the string
/// overloads (explicit overrides).
/// </summary>
public bool ModelExplicitlyConfigured { get; init; }
}

public static AISettings GetSettings(IConfiguration configuration)
{
Expand All @@ -21,7 +30,10 @@ public static AISettings GetSettings(IConfiguration configuration)
var model = GetModel(configuration, provider);
var timeoutSeconds = GetTimeoutSeconds(configuration);

return new AISettings(provider, deploymentName, model, timeoutSeconds);
return new AISettings(provider, deploymentName, model, timeoutSeconds)
{
ModelExplicitlyConfigured = !string.IsNullOrEmpty(configuration["AI:Model"])
};
}

public static AIProvider GetProvider(IConfiguration configuration)
Expand Down Expand Up @@ -61,14 +73,22 @@ public static string GetModel(IConfiguration configuration, AIProvider? provider
var model = provider switch
{
AIProvider.Ollama => "llama3.2",
AIProvider.AzureOpenAI => "gpt-4o",
AIProvider.GitHubModels => "openai/gpt-4o-mini",
AIProvider.AzureAIFoundry => "phi-3.5-mini",
AIProvider.AzureOpenAI => "gpt-5",
AIProvider.GitHubModels => "openai/gpt-5-mini",
// Foundry Local runs small on-device models; cloud Azure AI Foundry defaults to a
// hosted OpenAI model. These names mirror the strongly-typed catalog constants the
// AppHost deploys (FoundryModel.Local.Qwen2515b / FoundryModel.OpenAI.Gpt5Mini) so the
// advertised AI:Model matches the deployed model. qwen2.5-1.5b reliably emits tool
// calls locally (the phi-4-mini Foundry build does not).
AIProvider.AzureAIFoundry => IsFoundryLocal(configuration) ? "qwen2.5-1.5b" : "gpt-5-mini",
_ => throw new InvalidOperationException($"No default model available for provider: {provider}")
};
return model;
}

private static bool IsFoundryLocal(IConfiguration configuration) =>
configuration["AI:Provider"]?.ToLowerInvariant() == "foundrylocal";

public static int GetTimeoutSeconds(IConfiguration configuration)
{
var timeoutString = configuration["AI:TimeoutSeconds"];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.9" />
</ItemGroup>
</Project>
Loading