Skip to content

Commit 6eda06f

Browse files
committed
docs: update copilot instructions for clarity and completeness
1 parent 79428a2 commit 6eda06f

1 file changed

Lines changed: 101 additions & 70 deletions

File tree

.github/copilot-instructions.md

Lines changed: 101 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
**Common Commands** (from repository root):
66

77
```powershell
8-
# Backend (with Aspire Dashboard)
8+
# Backend (with Aspire Dashboard - recommended)
99
dotnet run --project src/TaskAgent.AppHost
1010
1111
# Backend (standalone)
@@ -20,6 +20,15 @@ pnpm dev
2020
# EF Migrations (from src/backend/services/TaskAgent/src/)
2121
dotnet ef migrations add MigrationName --context TaskDbContext --project TaskAgent.Infrastructure --startup-project TaskAgent.WebApi --output-dir Migrations/TaskDb
2222
dotnet 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
6873
using IServiceScope scope = _serviceProvider.CreateScope();
6974
var 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

Comments
 (0)