The ShoppingAgent feature introduced modern .NET patterns. The following items track applying these patterns to the legacy parts of the application (existing entities, controllers, and services). Read Directory.Build.props for .NET version, Directory.Packages.props for package versions, and .config/dotnet-tools.json for tool versions — do not hardcode these values.
- Split
ConversationManagerinto focused services: separate LLM communication, tool execution orchestration, and fallback/retry logic -
IConversationManager.ProcessAsyncacceptsList<ChatMessage>because the implementation mutates it (adds assistant/tool messages). Consider redesigning to return new messages instead of mutating the shared list, then change the parameter toIReadOnlyList<ChatMessage>
- Enable NRTs globally across the solution (
<Nullable>enable</Nullable>inDirectory.Build.props) and fix all resulting warnings — currently only the ShoppingAgent project has NRTs enabled
- Add constructors +
private settoArticle,Recipe(likeShoppingSession,OnlineArticleMapping) - Create strongly typed IDs (
ArticleId,MealId,RecipeId,UnitId,StoreId,ArticleGroupId) asreadonly record struct(pattern: seeShoppingSessionId.cs) - Register ID value conversions in
EfCoreContext.OnModelCreatingviaHasConversion - Update all repositories and callers to use typed IDs instead of
int
- Migrate
UnitsControllertoTypedResultsreturn types (likeSessionsController) - Add
ProblemDetailserror responses where missing - Add
CancellationTokenparameter to all controller actions (e.g.,UnitsController.GetUnits()) - Thread
CancellationTokenthrough all service and repository async calls
- Inject
TimeProviderinstead ofDateTime.Now/DateTimeOffset.UtcNow - Review return types: use
IEnumerable<T>when only iterating,IReadOnlyList<T>when count/index needed - Make all async service methods accept
CancellationToken
- Ensure all DTOs use
recordwithinitproperties (fixNewMealDtomutable properties) - Verify all DTOs have mapping extension methods (
ToDto(),ToEntity())
- Add
IStringLocalizer+.resxfor user-facing strings in legacy controllers - Add
ActivitySourceinstrumentation to old service operations for OpenTelemetry tracing - Evaluate
IOptions<T>pattern for any hardcoded configuration values in services
- ✅ Resolved: ShoppingAgent now runs server-side (Blazor Server / InteractiveServer). All traces and metrics are emitted directly into the server-side OpenTelemetry pipeline and reach the Aspire Dashboard.
- ✅ Resolved: No WASM app to boot — the ShoppingAgent Razor components render server-side via SignalR. Standard
HttpClient-based system tests cover the full application. - ✅ Resolved: Live LLM integration tests are available at
Tests/LlmIntegration/for end-to-end ShoppingAgent validation with a real Mistral client.
The Tests/LlmIntegration/ test suite validates the ShoppingAgent end-to-end with a real Mistral API client. These tests are opt-in only and excluded from normal CI runs.
- A valid Mistral API key: https://console.mistral.ai/
- The key must be set via the
LlmClient__ApiKeyenvironment variable
-
Set the API key (PowerShell):
$env:LlmClient__ApiKey = 'your-mistral-api-key'
Or (Bash):
export LlmClient__ApiKey='your-mistral-api-key'
-
Run the full suite:
dotnet test --filter "Category=LlmIntegration"
-
Run a specific test:
dotnet test --filter "Category=LlmIntegration&Name~ResearchPhase_SearchProducts"
The suite covers all user-facing ShoppingAgent flows:
- Research Phase: product search, details retrieval, preference management
- Clarification Phase: multi-turn clarification conversations
- Confirmation Phase: shopping list review and approval
- Cart Phase: add/remove items, view cart, navigate to checkout
- Shop Switching: switching shops and resetting state
- Multi-Step Workflows: complete end-to-end shopping scenarios
- Resilience: empty results, consecutive requests, conversation state preservation
- Tests use a real Mistral client to exercise LLM reasoning
- A scripted shop tool executor provides deterministic, repeatable behavior (no real shop API calls)
- Behavioral assertions only: tests verify tool execution and state transitions, not exact LLM wording
- Tests are marked
[Explicit]so they never run unless explicitly requested - All tests include
[Category("LlmIntegration")]for easy filtering
These tests are automatically excluded from GitHub Actions CI runs. The normal test command:
dotnet testwill skip all LlmIntegration tests. This keeps CI fast and prevents API key exposure.
Each live test makes real API calls to Mistral, incurring token consumption. Running the full suite (~19 tests) typically costs less than $0.01 USD.