55** Common Commands** (from repository root):
66
77``` powershell
8- # Backend (with Aspire Dashboard)
8+ # Backend (with Aspire Dashboard - recommended )
99dotnet run --project src/TaskAgent.AppHost
1010
1111# Backend (standalone)
@@ -20,6 +20,15 @@ pnpm dev
2020# EF Migrations (from src/backend/services/TaskAgent/src/)
2121dotnet ef migrations add MigrationName --context TaskDbContext --project TaskAgent.Infrastructure --startup-project TaskAgent.WebApi --output-dir Migrations/TaskDb
2222dotnet ef database update --context TaskDbContext --project TaskAgent.Infrastructure --startup-project TaskAgent.WebApi
23+
24+ # Testing
25+ cd src/backend/services/TaskAgent # Backend tests (132 tests)
26+ dotnet test # All tests
27+ dotnet test --filter "UnitTests" # Unit tests only
28+
29+ cd src/frontend/task-agent-web # Frontend tests (108 tests)
30+ pnpm test:run # Vitest unit tests (71)
31+ pnpm e2e # Playwright E2E tests (37)
2332```
2433
2534** Key URLs** :
@@ -28,123 +37,145 @@ dotnet ef database update --context TaskDbContext --project TaskAgent.Infrastruc
2837- Aspire Dashboard: https://localhost:17198
2938- AG-UI endpoint: https://localhost:5001/agui
3039
31- ## Project Overview
32-
33- AI-powered task management system built with ** Microsoft Agent Framework** (preview), demonstrating autonomous AI agents with function calling, Clean Architecture, and production-grade observability.
34-
35- ** Tech Stack** : .NET 10, ASP.NET Core MVC, Azure OpenAI (GPT-4o-mini), Entity Framework Core, .NET Aspire 13.0.2, OpenTelemetry
40+ ## Architecture Overview
3641
37- ** Frontend ** : Next.js 16, React 19, TypeScript, Tailwind CSS 4, SSE streaming
42+ AI-powered task management with ** Microsoft Agent Framework ** (preview), Clean Architecture, and dual-database persistence.
3843
39- ## Architecture
44+ ** Tech Stack ** : .NET 10, Azure OpenAI (GPT-4o-mini), EF Core, .NET Aspire 13.0.2 | Next.js 16, React 19, TypeScript
4045
41- ** Clean Architecture** with strict downward dependencies: ` Domain ` → ` Application ` → ` Infrastructure ` → ` WebApi `
42-
43- ** Critical** : Domain has NO external dependencies. Application defines interfaces (e.g., ` ITaskRepository ` ); Infrastructure implements them.
46+ ** Clean Architecture** (strict downward dependencies):
4447
4548```
46- src/
47- ├── TaskAgent.AppHost/ # Aspire orchestrator
48- ├── backend/services/TaskAgent/src/ # Clean Architecture (.NET)
49- │ ├── TaskAgent.Domain/ # Entities, Enums, Constants (NO dependencies)
50- │ ├── TaskAgent.Application/ # DTOs, Interfaces, Functions (TaskFunctions.cs)
51- │ ├── TaskAgent.Infrastructure/ # EF Core, Repositories, Azure Services
52- │ └── TaskAgent.WebApi/ # Controllers, AG-UI setup, DI
53- └── frontend/task-agent-web/ # Next.js + SSE streaming
49+ src/backend/services/TaskAgent/src/
50+ ├── TaskAgent.Domain/ # Entities, Enums, Constants (NO dependencies)
51+ ├── TaskAgent.Application/ # DTOs, Interfaces, Functions (TaskFunctions.cs)
52+ ├── TaskAgent.Infrastructure/ # EF Core, Repositories, Azure Services
53+ └── TaskAgent.WebApi/ # Controllers, AG-UI setup, DI configuration
5454```
5555
56- ## AI Agent Pattern
56+ ## Critical Patterns
5757
58- Uses ` Microsoft.Agents.AI.OpenAI ` with ** AG-UI Protocol** for SSE streaming.
58+ ### 1. Domain Entity Factory Methods
59+ ``` csharp
60+ // ❌ NEVER: new TaskItem() { Title = "..." }
61+ // ✅ ALWAYS: TaskItem.Create(title, description, priority)
62+ var task = TaskItem .Create (" My Task" , " Description" , TaskPriority .High );
5963
60- ** Key Files ** :
61- - ` WebApi/Extensions/AgentServiceExtensions.cs ` - Agent factory with ChatMessageStore
62- - ` WebApi/Constants/AgentInstructions.cs ` - Single source for agent behavior
63- - ` Application/Functions/TaskFunctions .cs` - 6 function tools (CreateTask, ListTasks, etc.)
64+ // Business rules in entity methods
65+ task . UpdateStatus ( TaskStatus . InProgress ); // Validates transitions internally
66+ ```
67+ See: ` Domain/Entities/TaskItem .cs`
6468
65- ** Critical Pattern - Scoped Dependencies** :
69+ ### 2. Scoped Dependencies in Singleton Agent
6670``` csharp
67- // TaskFunctions takes IServiceProvider, creates scope per-call for fresh DbContext
71+ // TaskFunctions is used by singleton AIAgent, but needs scoped DbContext
72+ // ✅ Create scope per-call for fresh DbContext
6873using IServiceScope scope = _serviceProvider .CreateScope ();
6974var repository = scope .ServiceProvider .GetRequiredService <ITaskRepository >();
7075```
76+ See: ` Application/Functions/TaskFunctions.cs `
7177
72- ** Function Tools Contract** : All methods in ` TaskFunctions.cs ` must:
78+ ### 3. Function Tools Contract
79+ All methods in ` TaskFunctions.cs ` must:
7380- Use ` [Description] ` attributes for AI understanding
7481- Return user-friendly strings (✅/❌ emojis) - ** NEVER throw exceptions**
7582- Catch all exceptions, return formatted error strings
7683
77- ## Domain Patterns
78-
84+ ### 4. PostgreSQL JSON Storage
7985``` csharp
80- // ❌ NEVER: new TaskItem() { Title = "..." }
81- // ✅ ALWAYS: TaskItem.Create(title, description, priority)
86+ // ✅ Use json (preserves property order for $type discriminator)
87+ entity .Property (e => e .SerializedThread ).HasColumnType (" json" );
88+ // ❌ NEVER jsonb (reorders properties alphabetically, breaks polymorphic deserialization)
8289
83- // Business rules in entity methods
84- task .UpdateStatus (TaskStatus .InProgress ); // Validates transitions
90+ // ✅ Use GetRawText() to preserve exact JSON structure
91+ string serialized = threadJson .GetRawText ();
92+ // ❌ NEVER JsonSerializer.Serialize(threadJson) - reorders properties
8593```
8694
87- ## API Endpoints
95+ ## Dual Database Architecture
96+
97+ - ** SQL Server** (` TaskDbContext ` ) - Task entities (structured CRUD)
98+ - ** PostgreSQL** (` ConversationDbContext ` ) - Conversation threads (JSON blob storage)
8899
89- ** SSE Streaming** (Frontend uses these):
100+ Both databases ** MUST be available** on startup (fail-fast strategy).
101+
102+ ## SSE Streaming & AG-UI
103+
104+ ** Endpoints** :
90105- ` POST /api/agent/chat ` - Send message (SSE stream response)
91106- ` GET /api/conversations ` - List conversations
92107- ` GET /api/conversations/{threadId}/messages ` - Get history
93108- ` DELETE /api/conversations/{threadId} ` - Delete conversation
94109
95- ** SSE Event Types** : ` TEXT_MESSAGE_START ` , ` TEXT_MESSAGE_CONTENT ` , ` TEXT_MESSAGE_END ` , ` TOOL_CALL_START ` , ` TOOL_CALL_RESULT ` , ` CONTENT_FILTER ` , ` THREAD_STATE `
110+ ** SSE Event Types** : ` STEP_STARTED ` , ` STATUS_UPDATE ` , ` STEP_FINISHED ` , ` TEXT_MESSAGE_START ` , ` TEXT_MESSAGE_CONTENT ` , ` TEXT_MESSAGE_END ` , ` TOOL_CALL_START ` , ` TOOL_CALL_RESULT ` , ` CONTENT_FILTER ` , ` THREAD_STATE `
96111
97- ## Dual Database Architecture
112+ ** Dynamic Status Messages ** : ` FunctionDescriptionProvider ` generates status from ` [Description] ` attributes (multi-agent ready, no hardcoded mappings).
98113
99- - ** SQL Server** (` TaskDbContext ` ) - Task entities
100- - ** PostgreSQL** (` ConversationDbContext ` ) - Conversation threads (JSON blob storage)
101-
102- Both databases ** MUST be available** on startup (fail-fast strategy).
114+ ** Content Safety** : Azure OpenAI's built-in filtering → Backend catches ` ClientResultException ` → Sends ` CONTENT_FILTER ` SSE event → Frontend displays friendly message in chat.
103115
104- See ` docs/DUAL_DATABASE_ARCHITECTURE.md ` for rationale.
116+ ## Frontend Patterns
105117
106- ## Content Safety
118+ ### SSE Streaming Client
119+ ``` typescript
120+ // ✅ Use chat-service.ts for all backend communication
121+ import { sendMessage , listConversations } from " @/lib/api/chat-service" ;
107122
108- Uses ** Azure OpenAI's built-in content filtering** (no separate SDK). When triggered:
109- 1 . Backend catches ` ClientResultException ` with ` content_filter ` code
110- 2 . Sends ` CONTENT_FILTER ` SSE event
111- 3 . Frontend displays friendly message in chat
123+ // ✅ StreamingCallbacks for progressive UI updates
124+ await sendMessage (request , {
125+ onTextChunk : (delta , fullText ) => setMessage (fullText ),
126+ onToolCallStart : (name , id ) => setLoading (true ),
127+ onComplete : (state ) => saveThreadState (state ),
128+ });
129+ ```
130+ See: ` frontend/lib/api/chat-service.ts `
112131
113- See ` docs/CONTENT_SAFETY.md ` for 75+ test cases.
132+ ### Component Organization
133+ ```
134+ components/
135+ ├── chat/ # ChatInput, ChatMessage, ChatMessagesList
136+ ├── conversations/ # ConversationSidebar, ConversationList, ConversationItem
137+ └── shared/ # LoadingIndicator, DeleteConfirmModal
138+ ```
114139
115- ## Anti-Patterns
140+ ## Anti-Patterns to Avoid
116141
117- ❌ ` new TaskItem() ` → Use ` TaskItem.Create() ` factory
118- ❌ Inject scoped DbContext into singleton agent → Use ` IServiceProvider.CreateScope() `
119- ❌ Throw from function tools → Return user-friendly error strings
120- ❌ Skip ` .AsNoTracking() ` on read queries → Performance degradation
121- ❌ Magic strings/numbers → Use constants from appropriate layer
122- ❌ npm/yarn for frontend → Use ` pnpm ` (enforced by pnpm-lock.yaml)
142+ | ❌ Don't | ✅ Do Instead |
143+ | ----------| ---------------|
144+ | ` new TaskItem() ` | ` TaskItem.Create() ` factory |
145+ | Inject scoped DbContext into singleton | ` IServiceProvider.CreateScope() ` |
146+ | Throw from function tools | Return user-friendly error strings |
147+ | Skip ` .AsNoTracking() ` on reads | Always use for read-only queries |
148+ | Magic strings/numbers | Use constants from appropriate layer |
149+ | npm/yarn for frontend | Use ` pnpm ` (enforced by pnpm-lock.yaml) |
150+ | ` jsonb ` for conversation storage | ` json ` (preserves property order) |
123151
124152## Version Constraints
125153
126- ** These versions MUST match** (see ` src/global.json ` and ` src/Directory.Build.props ` ):
127- - .NET SDK: 10.0.0
128- - Aspire: 13.0.2
129- - Target Framework: net10.0
154+ ** Pinned versions** (see ` src/global.json ` and ` src/Directory.Packages.props ` ):
155+ - .NET SDK: 10.0.0 | Aspire: 13.0.2 | Target: net10.0
156+ - Microsoft.Agents.AI.OpenAI: ` 1.0.0-preview.251125.1 ` (preview - pin exactly)
130157
131158** Central Package Management** : All NuGet versions in ` src/Directory.Packages.props `
132159
133160## Key Files Reference
134161
135162| File | Purpose |
136163| ------| ---------|
137- | ` WebApi/Extensions/AgentServiceExtensions.cs ` | AG-UI + ChatMessageStore setup |
138- | ` WebApi/Constants/AgentInstructions.cs ` | Agent behavior prompt |
139- | ` Application/Functions/TaskFunctions.cs ` | Function tools for AI |
164+ | ` WebApi/Extensions/AgentServiceExtensions.cs ` | AIAgent factory + ChatMessageStore |
165+ | ` WebApi/Services/FunctionDescriptionProvider.cs ` | Dynamic status from [ Description] attributes |
166+ | ` WebApi/Services/SseStreamingService.cs ` | SSE events (STEP_STARTED, STATUS_UPDATE, STEP_FINISHED) |
167+ | ` WebApi/Constants/AgentInstructions.cs ` | Agent system prompt |
168+ | ` Application/Functions/TaskFunctions.cs ` | 6 function tools (CreateTask, ListTasks, etc.) |
140169| ` Domain/Entities/TaskItem.cs ` | Core entity with factory method |
141- | ` Infrastructure/MessageStores/PostgresChatMessageStore.cs ` | AG-UI persistence |
170+ | ` Infrastructure/Services/AgentStreamingService.cs ` | Core streaming + content filter detection |
171+ | ` Infrastructure/Services/PostgresThreadPersistenceService.cs ` | JSON blob storage for threads |
172+ | ` frontend/lib/api/chat-service.ts ` | SSE streaming client |
173+ | ` frontend/hooks/use-chat.ts ` | Chat state management hook |
142174
143175## Additional Documentation
144176
145- For detailed information, see the ` docs/ ` folder:
146- - ` DUAL_DATABASE_ARCHITECTURE.md ` - Why SQL Server + PostgreSQL
147- - ` CONTENT_SAFETY.md ` - Security testing guide (75+ test cases)
148- - ` POSTGRESQL_MIGRATION.md ` - Database setup guide
149- - ` LESSONS_LEARNED.md ` - Project-wide patterns and best practices
150- - ` FRONTEND_E2E_TESTING.md ` - Frontend testing scenarios
177+ - ` docs/LESSONS_LEARNED.md ` - Project-wide patterns and trade-offs
178+ - ` docs/DUAL_DATABASE_ARCHITECTURE.md ` - Why SQL Server + PostgreSQL
179+ - ` docs/CONTENT_SAFETY.md ` - Security testing (75+ test cases)
180+ - ` src/backend/services/TaskAgent/TESTING_STRATEGY.md ` - Backend testing (132 tests)
181+ - ` src/frontend/task-agent-web/TESTING_STRATEGY.md ` - Frontend testing (108 tests)
0 commit comments