Files
Tommaso Stocchi 60af59ba8b .NET: Features/3768-devui-aspire-integration (#3771)
* adds devui integration and samples

* adds unit tests for devui integration

* fix: correct formatting of copyright notice in unit test files

* fixes formatting issues

* fixes build for net8 target

* fixes formatting errors on test apphost

* adds copyright notice to multiple files and removes unnecessary using directives

* Update dotnet/aspire-integration/Aspire.Hosting.AgentFramework.DevUI/DevUIAggregatorHostedService.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/aspire-integration/Aspire.Hosting.AgentFramework.DevUI/DevUIAggregatorHostedService.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/tests/Aspire.Hosting.AgentFramework.DevUI.UnitTests/Aspire.Hosting.AgentFramework.DevUI.UnitTests.csproj

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/samples/DevUIIntegration/DevUIIntegration.AppHost/DevUIIntegration.AppHost.csproj

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/aspire-integration/Aspire.Hosting.AgentFramework.DevUI/DevUIAggregatorHostedService.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Refactor project files to use TargetFrameworks instead of TargetFramework for multi-targeting support; add optional port property to DevUIResource class.

* Add unit tests for DevUIAggregatorHostedService; refactor project files for TargetFrameworks support

* Refactor project files to use TargetFrameworks for multi-targeting support in DevUIIntegration samples

* Remove unnecessary using directive for Aspire.Hosting in DevUIAggregatorHostedServiceTests

* merge

* fixes Conversation routing for non-first backends

* add documentation for devui integration sample

* update project references in solution file for improved integration

* fixes package versions post merge

* move Aspire.Hosting.AgentFramework.DevUI to dotnet/src

Move the project from aspire-integration/ to src/ to be consistent
with the location of all other projects in the repo.

* move DevUI sample to samples/05-end-to-end/DevUIAspireIntegration

Move the sample from samples/DevUIIntegration/ to
samples/05-end-to-end/DevUIAspireIntegration/ to match the location
of other end-to-end samples.

* remove unnecessary net472 framework condition from sample csproj files

These projects only target net10.0, so the
Condition="'$(TargetFramework)' != 'net472'" on ItemGroup is unnecessary.

* update sample model name from gpt-4.1 to gpt-5.4

Use a more up-to-date model name in the DevUI integration samples.

* Revert "remove unnecessary net472 framework condition from sample csproj files"

This reverts commit 08cf41253b.

* fix: use TargetFrameworks to override multi-targeting from Directory.Build.props

The parent Directory.Build.props sets TargetFrameworks to net10.0;net472,
which overrides the singular TargetFramework in each csproj. Use the plural
TargetFrameworks property set to net10.0 only to properly override it, and
remove the now-unnecessary net472 condition on ItemGroup.

* fixes aspire config

* fix: update Microsoft.Extensions packages to version 10.0.1

* Address Copilot review feedback on DevUI Aspire integration

- Fix request body dropping in ProxyConversationsAsync: always read the
  body when ContentLength > 0 before routing, then pass it through to
  all proxy calls (previously null was passed when backend was resolved
  from query param or conversation map)
- Fix resource leak: dispose aggregator on startup failure in catch block
- Fix XML docs: accurately describe embedded resource serving behavior
- Remove reflection from DevUIResourceTests (InternalsVisibleTo already set)
- Make sensitive telemetry conditional on Development environment in samples

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: update chat client version to gpt41 in both EditorAgent and WriterAgent

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
60af59ba8b · 2026-04-20 11:12:54 +00:00
History
..

DevUI Integration Sample

This sample demonstrates how to use the Aspire.Hosting.AgentFramework.DevUI library to test and debug multiple AI agents through a unified DevUI web interface, orchestrated by an Aspire AppHost.

The solution contains two agent services:

  • WriterAgent — a simple agent that writes short stories (≤ 300 words) about a given topic.
  • EditorAgent — an agent that edits stories for grammar and style, selects a title, and formats the result for publishing. It also demonstrates tool use via AIFunctionFactory.

Prerequisites

Azure AI Foundry configuration

The sample requires an Azure AI Foundry resource with a deployed gpt-4.1 model. You have two options:

Option 1: Connect to an existing Foundry resource

Fill in the parameters in DevUIIntegration.AppHost/appsettings.json:

{
    "Azure": {
        "TenantId": "<your-tenant-id>",
        "SubscriptionId": "<your-subscription-id>",
        "AllowResourceGroupCreation": true,
        "ResourceGroup": "<your-resource-group>",
        "Location": "<your-azure-region>",
        "CredentialSource": "AzureCli"
    },
    "Parameters": {
        "existingFoundryName": "<your-foundry-resource-name>",
        "existingFoundryResourceGroup": "<resource-group-containing-your-foundry>"
    }
}

The AppHost calls foundry.AsExisting(...) with these parameters, so Aspire connects to the existing resource instead of provisioning a new one.

Option 2: Let Aspire provision a new Foundry resource

Remove or comment out the AsExisting block in DevUIIntegration.AppHost/Program.cs:

// Comment the following lines to create a new Foundry instance
// _ = builder.AddParameterFromConfiguration("tenant", "Azure:TenantId");
// var existingFoundryName = builder.AddParameter("existingFoundryName") ...
// foundry.AsExisting(existingFoundryName, existingFoundryResourceGroup);

Aspire will provision a new Azure AI Foundry resource on startup. The DevUI resource uses .WaitFor(foundry) transitively through the agent services, so the frontend won't become available until provisioning completes. This can take several minutes on first run.

You still need to fill in the Azure section of appsettings.json (subscription, location, etc.) so Aspire knows where to create the resource.

Agent name matching with WithAgentService

When connecting agent services to DevUI in the AppHost, you must pass the correct agent name via the agents: parameter. This name must match the name used in AddAIAgent(...) inside each agent service's Program.cs — not the Aspire resource name.

For example, the WriterAgent Aspire resource is named "writer-agent", but the agent is registered as "writer":

// WriterAgent/Program.cs
builder.AddAIAgent("writer", "You write short stories ...");
//                  ^^^^^^^^ this is the agent name
// EditorAgent/Program.cs
builder.AddAIAgent("editor", (sp, key) => { ... });
//                  ^^^^^^^^ this is the agent name

The AppHost must use these exact names:

// DevUIIntegration.AppHost/Program.cs
builder.AddDevUI("devui")
    .WithAgentService(writerAgent, agents: [new("writer")])   // ✅ matches AddAIAgent("writer", ...)
    .WithAgentService(editorAgent, agents: [new("editor")])   // ✅ matches AddAIAgent("editor", ...)
    .WaitFor(writerAgent)
    .WaitFor(editorAgent);

Using the wrong name (e.g., new("writer-agent") instead of new("writer")) will cause the aggregator to send an entity ID the backend doesn't recognize, resulting in 404 errors when interacting with the agent.

If you omit the agents: parameter entirely, the aggregator defaults to a single agent named after the Aspire resource (e.g., "writer-agent"). Since agent services don't expose a /v1/entities discovery endpoint, the Aspire resource name must exactly match the agent name registered via AddAIAgent(...) in the service's Program.cs.

Running the sample

cd dotnet/samples/05-end-to-end/DevUIAspireIntegration
aspire run

Once all services are running, open the DevUI URL shown in the Aspire dashboard. You should see both the writer and editor agents listed — select one and start a conversation.