Skip to content

Add local developlment experience using Aspire - #15

Merged
philasmar merged 11 commits into
devfrom
asmarp/local-dev
May 22, 2026
Merged

Add local developlment experience using Aspire#15
philasmar merged 11 commits into
devfrom
asmarp/local-dev

Conversation

@philasmar

@philasmar philasmar commented May 20, 2026

Copy link
Copy Markdown
Contributor

Issue #, if available:
DOTNET-8675

Description of changes

Adds a complete local development experience for AWS AgentCore agents using .NET Aspire. Developers can press F5/Run and get a fully functional testing stack — agent app,
runtime emulator, memory emulator, and an interactive chat UI — with zero AWS credentials required for the core development loop.

What's included

AWS.AgentCore.Testing NuGet package — A self-contained package that provides:

  • Runtime Emulator — An embedded Kestrel server exposing the SDK-compatible POST /runtimes/{arn}/invocations endpoint. The AWS SDK talks to this emulator identically to
    how it talks to the real AgentCore Runtime service.
  • Memory Emulator — An in-memory implementation of the ListEvents/CreateEvent APIs, enabling AgentCoreMemoryProvider to persist conversation history locally without AWS.
  • Chat App UI — A Blazor Server application with a configurable JSON payload editor, dynamic parameters, built-in templates, code editor, light/dark theme, and streaming
    support.
  • Aspire ExtensionsAddAgentCoreRuntime<T>(), WithStreaming(), WithInMemory(), and WithReference() for wiring everything together.

Key design decisions:

  • AddAgentCoreRuntime<T>() returns IResourceBuilder<ProjectResource>, making it fully compatible with Aspire deployment features like PublishAsECSFargateService() from
    Aspire.Hosting.AWS.
  • WithReference(agent) injects AGENTCORE_SERVICE_ENDPOINT as an environment variable, allowing consuming web apps to override the AWS SDK's ServiceURL and communicate
    through the runtime emulator using the same SDK code they'd use in production.
  • All emulators run in-process within the AppHost — no Docker, no separate processes.
  • The runtime emulator passes request payloads through as-is (no JSON wrapping), so agents receive exactly what the Chat UI or consuming app sends.

Sample apps:

  • AspireAppHost — Demonstrates registering multiple agents with streaming, memory, and WithReference for a standalone ChatBotUI.
  • ChatBotUI — A standalone Blazor web app that reads AGENTCORE_SERVICE_ENDPOINT and overrides the SDK's endpoint. Works identically against the local emulator and the real
    AWS service.
  • RemoteMcpAgent — Demonstrates connecting to remote MCP servers and registering their tools with the Microsoft Agent Framework at invocation time.

Usage

var builder = DistributedApplication.CreateBuilder(args);

var agent = builder.AddAgentCoreRuntime<Projects.MyAgent>()
    .WithStreaming()
    .WithInMemory();

// Wire a web app to the agent's runtime emulator
builder.AddProject<Projects.MyChatApp>("chat")
    .WithReference(agent);

// Compatible with Aspire.Hosting.AWS deployment
agent.PublishAsECSFargateService();

builder.Build().Run();

Note

▎ The Aspire extension methods (AddAgentCoreRuntime, WithStreaming, WithInMemory, WithReference) currently live in the AWS.AgentCore.Testing package. Once AWS.AgentCore.Testing
▎ is published to NuGet, these extensions should be migrated to the Aspire.Hosting.AWS package to align with the standard Aspire integration pattern where hosting extensions
▎ live in the Aspire.Hosting.* namespace.

Test plan

  • Unit tests pass (129 tests across 3 projects)
  • Integration tests discover and run via DistributedApplicationTestingBuilder
  • Solution builds with zero errors and zero warnings
  • Run AppHost locally — verify Chat UI loads, agent responds, memory persists across turns
  • Verify WithReference flow — ChatBotUI receives AGENTCORE_SERVICE_ENDPOINT and invokes agent successfully
  • Verify streaming mode — responses stream incrementally in the Chat UI
  • Verify NuGet packaging — dotnet pack produces valid package with wwwroot assets
  • Verify RemoteMcpAgent — connects to DeepWiki MCP server and tools are available

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@philasmar philasmar added the Release Not Needed Add this label if a PR does not need to be released. label May 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an Aspire-based local development stack for AWS.AgentCore, centered on a new AWS.AgentCore.Testing package that embeds an in-process Runtime emulator, Memory emulator, and a Blazor chat UI so developers can run agents locally with an F5 workflow.

Changes:

  • Added AWS.AgentCore.Testing package: embedded runtime + memory emulators, embedded Blazor Chat UI, and Aspire hosting extensions (AddAgentCoreRuntime, WithStreaming, WithInMemory, WithReference).
  • Updated AWS.AgentCore and ChatBotUI to support Aspire/local endpoint overrides via environment variables.
  • Added sample AppHost + Remote MCP agent sample plus extensive unit/property/integration test coverage for the new testing components.

Reviewed changes

Copilot reviewed 75 out of 78 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
test/AWS.AgentCore.Testing.UnitTests/RuntimeEmulatorServiceTests.cs Unit tests for runtime emulator request formatting/headers
test/AWS.AgentCore.Testing.UnitTests/RuntimeEmulatorServicePropertyTests.cs Property tests for runtime emulator uniqueness/concurrency
test/AWS.AgentCore.Testing.UnitTests/InMemoryEventStoreTests.cs Unit tests for in-memory memory-event store behavior
test/AWS.AgentCore.Testing.UnitTests/InMemoryEventStorePropertyTests.cs Property tests for store round-trip/ordering/pagination/isolation
test/AWS.AgentCore.Testing.UnitTests/GlobalUsings.cs Global test usings
test/AWS.AgentCore.Testing.UnitTests/AWS.AgentCore.Testing.UnitTests.csproj Unit test project definition
test/AWS.AgentCore.Testing.UnitTests/AgentCoreTestingPropertyTests.cs Property tests for Aspire extension invariants
test/AWS.AgentCore.Testing.UnitTests/AgentCoreTestingExtensionsTests.cs Unit tests for Aspire extension API surface
test/AWS.AgentCore.Testing.IntegrationTests/GlobalUsings.cs Global integration-test usings
test/AWS.AgentCore.Testing.IntegrationTests/AWS.AgentCore.Testing.IntegrationTests.csproj Integration test project definition
test/AWS.AgentCore.Testing.IntegrationTests/AspireIntegrationTests.cs Aspire-hosted end-to-end smoke tests
src/AWS.AgentCore/Extensions/AgentCoreBuilderExtensions.cs Add Aspire-managed port binding + local service endpoint override
src/AWS.AgentCore/Constants.cs Adds env var constants for service endpoint + Aspire managed mode
src/AWS.AgentCore.Testing/wwwroot/aws.svg Dark theme logo asset
src/AWS.AgentCore.Testing/wwwroot/aws-light.svg Light theme logo asset
src/AWS.AgentCore.Testing/wwwroot/app.css Base styling for embedded chat UI
src/AWS.AgentCore.Testing/Services/PortAllocator.cs Utility for local port selection
src/AWS.AgentCore.Testing/Services/ChatSessionManager.cs In-memory chat session state for UI
src/AWS.AgentCore.Testing/Services/AspireLoggerProvider.cs Bridges embedded server logs into Aspire dashboard
src/AWS.AgentCore.Testing/Services/AgentCoreService.cs Chat UI service to invoke runtime (non-streaming + streaming)
src/AWS.AgentCore.Testing/RuntimeEmulatorServer.cs Embedded Kestrel runtime emulator host
src/AWS.AgentCore.Testing/Program.cs Placeholder entry point for Web SDK output type
src/AWS.AgentCore.Testing/Models/ChatSession.cs Chat session model
src/AWS.AgentCore.Testing/Models/ChatMessage.cs Chat message model + role enum
src/AWS.AgentCore.Testing/Models/AgentCoreSettings.cs Chat UI settings/options model
src/AWS.AgentCore.Testing/MemoryEmulatorServer.cs Embedded Kestrel memory emulator host
src/AWS.AgentCore.Testing/Emulators/Runtime/RuntimeEmulatorService.cs Runtime emulator forwarding + session tracking
src/AWS.AgentCore.Testing/Emulators/Runtime/Models/StreamThroughResult.cs Runtime streaming passthrough result model
src/AWS.AgentCore.Testing/Emulators/Runtime/Models/SessionState.cs Runtime session state model
src/AWS.AgentCore.Testing/Emulators/Runtime/Models/PromptSubmission.cs Runtime prompt submission model
src/AWS.AgentCore.Testing/Emulators/Runtime/Models/InvocationResult.cs Runtime invocation result model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/StoredEvent.cs Internal event storage model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/PayloadTypeModel.cs Memory wire-format payload wrapper model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/ListEventsApiResponse.cs Memory ListEvents response model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/EventModel.cs Memory event wire-format model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/CreateEventApiResponse.cs Memory CreateEvent response model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/CreateEventApiRequest.cs Memory CreateEvent request model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/ConversationalModel.cs Memory conversational payload model
src/AWS.AgentCore.Testing/Emulators/Memory/Models/ContentModel.cs Memory content model
src/AWS.AgentCore.Testing/Emulators/Memory/InMemoryEventStore.cs In-memory store implementation for memory emulator
src/AWS.AgentCore.Testing/Components/Routes.razor Blazor router setup
src/AWS.AgentCore.Testing/Components/Pages/NotFound.razor NotFound page
src/AWS.AgentCore.Testing/Components/Pages/Home.razor.css Main chat UI styling
src/AWS.AgentCore.Testing/Components/Pages/Error.razor Error page
src/AWS.AgentCore.Testing/Components/Layout/Sidebar.razor.css Sidebar styling
src/AWS.AgentCore.Testing/Components/Layout/Sidebar.razor Sidebar component
src/AWS.AgentCore.Testing/Components/Layout/ReconnectModal.razor.js Reconnect modal behavior
src/AWS.AgentCore.Testing/Components/Layout/ReconnectModal.razor.css Reconnect modal styling
src/AWS.AgentCore.Testing/Components/Layout/ReconnectModal.razor Reconnect modal markup
src/AWS.AgentCore.Testing/Components/Layout/MainLayout.razor.css Layout styling
src/AWS.AgentCore.Testing/Components/Layout/MainLayout.razor Layout component
src/AWS.AgentCore.Testing/Components/CodeEditor.razor.js Code editor JS (indentation/brackets/scroll sync)
src/AWS.AgentCore.Testing/Components/CodeEditor.razor.css Code editor styling
src/AWS.AgentCore.Testing/Components/CodeEditor.razor Code editor component
src/AWS.AgentCore.Testing/Components/App.razor App host document for embedded Blazor UI
src/AWS.AgentCore.Testing/Components/_Imports.razor Blazor imports for embedded UI
src/AWS.AgentCore.Testing/ChatAppServer.cs Embedded chat UI Kestrel host setup
src/AWS.AgentCore.Testing/build/AWS.AgentCore.Testing.targets MSBuild targets to copy packaged wwwroot assets
src/AWS.AgentCore.Testing/AWS.AgentCore.Testing.csproj Testing package project + packaging/build targets
src/AWS.AgentCore.Testing/AgentCoreTestingExtensions.cs Aspire hosting extensions to wire emulators/UI
sampleapps/RemoteMcpAgent/Startup.cs Sample agent startup wiring
sampleapps/RemoteMcpAgent/RemoteMcpAgent.csproj Sample project definition
sampleapps/RemoteMcpAgent/Models/PromptRequest.cs Sample invocation payload model
sampleapps/RemoteMcpAgent/McpToolProvider.cs Lazy MCP connection + tool discovery
sampleapps/RemoteMcpAgent/Dockerfile Container image build for sample
sampleapps/RemoteMcpAgent/Agent.cs Sample handler invoking agent framework with MCP tools
sampleapps/ChatBotUI/Services/AgentCoreService.cs Refactor to DI-injected BedrockAgentCore client
sampleapps/ChatBotUI/Program.cs Local runtime emulator endpoint override wiring
sampleapps/AspireAppHost/Properties/launchSettings.json AppHost launch profiles
sampleapps/AspireAppHost/Program.cs Sample AppHost wiring multiple agents/emulators
sampleapps/AspireAppHost/AspireAppHost.csproj AppHost project definition
AWS.AgentCore.slnx Adds new projects to solution
.kiro/specs/aspire-local-dev/tasks.md Implementation plan documentation
.kiro/specs/aspire-local-dev/requirements.md Requirements documentation
.kiro/specs/aspire-local-dev/design.md Design documentation
.kiro/specs/aspire-local-dev/.config.kiro Spec metadata
Comments suppressed due to low confidence (2)

src/AWS.AgentCore.Testing/Emulators/Runtime/RuntimeEmulatorService.cs:87

  • InvokeAgentStreamThroughAsync reads and returns response.Content as a Stream but the HttpResponseMessage is never disposed, and callers currently don't dispose the returned stream either. This is likely to leak connections, especially with repeated streaming invocations. Consider returning the HttpResponseMessage (or IDisposable wrapper) and disposing it after the response has been copied to the upstream response body.
    src/AWS.AgentCore.Testing/Emulators/Runtime/RuntimeEmulatorService.cs:112
  • WaitForAgentReadyAsync allocates an HttpResponseMessage on each GET /ping attempt but never disposes it. Please dispose the response (even when non-success) and consider accepting/passing a CancellationToken so AppHost shutdown or upstream request abort can stop the readiness polling promptly.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/AWS.AgentCore.Testing/RuntimeEmulatorServer.cs
Comment thread src/AWS.AgentCore.Testing/Emulators/Memory/InMemoryEventStore.cs Outdated
Comment thread src/AWS.AgentCore.Testing/Emulators/Memory/InMemoryEventStore.cs
Comment thread src/AWS.AgentCore/Extensions/AgentCoreBuilderExtensions.cs Outdated
Comment thread src/AWS.AgentCore.Testing/ChatAppServer.cs Outdated
Comment thread sampleapps/ChatBotUI/Program.cs Outdated
Comment thread src/AWS.AgentCore.Testing/Components/Layout/ReconnectModal.razor.css Outdated
Comment thread .kiro/specs/aspire-local-dev/requirements.md Outdated
Comment thread .kiro/specs/aspire-local-dev/design.md Outdated
@philasmar
philasmar marked this pull request as ready for review May 20, 2026 20:37
@philasmar
philasmar requested review from a team as code owners May 20, 2026 20:37
@philasmar
philasmar requested review from GarrettBeatty and normj May 20, 2026 20:37
@philasmar philasmar changed the title [DRAFT] Local Dev Experience Add local developlment experience using Aspire May 20, 2026
Comment thread src/AWS.AgentCore.Testing/Emulators/Memory/InMemoryEventStore.cs
Comment thread src/AWS.AgentCore.Testing/Emulators/Memory/Models/CreateEventApiRequest.cs Outdated
Comment thread src/AWS.AgentCore.Testing/Emulators/Memory/Models/EventModel.cs Outdated

@normj normj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Aspire dashboard the https://localhost endpoint is showing up along with the Chat and Agent links. But the localhost link returns a 404. Seems like the localhost endpoint isn't useful and we should figure out how to remove that.

Comment thread src/AWS.AgentCore.Testing/AWS.AgentCore.Testing.csproj Outdated
Comment thread src/AWS.AgentCore.Testing/Components/Pages/Home.razor Outdated
Comment thread src/AWS.AgentCore.Testing/Services/AgentCoreService.cs Outdated
Comment thread src/AWS.AgentCore.Testing/Services/AgentCoreService.cs Outdated
Comment thread src/AWS.AgentCore.Testing/Services/ChatSessionManager.cs Outdated
Comment thread src/AWS.AgentCore.Testing/Services/PortAllocator.cs Outdated
Comment thread sampleapps/AspireAppHost/AgentCoreTestingExtensions.cs
Comment thread src/AWS.AgentCore.Testing/Program.cs
@philasmar

Copy link
Copy Markdown
Contributor Author

In the Aspire dashboard the https://localhost endpoint is showing up along with the Chat and Agent links. But the localhost link returns a 404. Seems like the localhost endpoint isn't useful and we should figure out how to remove that.

This behavior was only on Windows which is why I didn't notice it. I fixed it for both platforms.

Comment thread src/AWS.AgentCore.Testing/Components/Pages/Home.razor Outdated
@philasmar
philasmar merged commit da32229 into dev May 22, 2026
3 checks passed
@dscpinheiro
dscpinheiro deleted the asmarp/local-dev branch June 29, 2026 02:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Release Not Needed Add this label if a PR does not need to be released.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants