Skip to content

Commit 0e0a907

Browse files
committed
docs: update README and copilot instructions for clarity
Updated README.md to include conversation persistence details and clarified the role of IThreadPersistenceService. Enhanced copilot instructions with body formatting guidelines and file listing best practices. Modified files (2): - README.md: Added conversation persistence section - .github/copilot-instructions.md: Updated body format and style
1 parent d83238a commit 0e0a907

3 files changed

Lines changed: 240 additions & 31 deletions

File tree

.github/copilot-instructions.md

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,41 @@ WebApp/ - Controllers, Middleware, DI setup, Agent factory (TaskAgentSe
1919

2020
## AI Agent Pattern
2121

22+
### Microsoft Agentic AI Framework
23+
24+
This project uses `Microsoft.Agents.AI.OpenAI` (preview) - Microsoft's framework for building autonomous AI agents with function calling.
25+
26+
**Key APIs**:
27+
28+
```csharp
29+
// 1. Get chat client from Azure OpenAI
30+
ChatClient chatClient = azureClient.GetChatClient(deploymentName);
31+
32+
// 2. Create agent with tools and instructions
33+
AIAgent agent = chatClient.CreateAIAgent(
34+
instructions: "System prompt with behavioral rules...",
35+
tools: [createTaskTool, listTasksTool, ...]
36+
);
37+
38+
// 3. Create conversation thread
39+
AgentThread thread = await agent.CreateThreadAsync();
40+
41+
// 4. Add user message
42+
await thread.AddUserMessageAsync("Create a high priority task");
43+
44+
// 5. Invoke agent (streams responses)
45+
await foreach (StreamingResponse response in thread.InvokeAsync(agent)) {
46+
if (response is StreamingTextResponse textResponse) {
47+
// Process streamed text
48+
}
49+
}
50+
51+
// 6. Serialize thread for persistence
52+
string serialized = thread.Serialize();
53+
```
54+
55+
**Thread lifecycle**: Each HTTP request loads thread, processes message, saves updated thread.
56+
2257
### Factory Method (`TaskAgentService.CreateAgent`)
2358

2459
```csharp
@@ -29,7 +64,7 @@ var agent = chatClient.CreateAIAgent(instructions: "...", tools: [...]);
2964
**Key Points**:
3065

3166
- Agent is **scoped per request** (registered in `DependencyInjection.AddPresentation()`) - never singleton
32-
- Each conversation gets a **thread ID** for context persistence via `_threads` dictionary
67+
- Each conversation gets a **thread ID** for context persistence via thread serialization
3368
- Instructions embed behavioral rules: immediate task creation, Markdown tables with emojis, contextual suggestions
3469
- Tools created with `AIFunctionFactory.Create(taskFunctions.MethodName)`
3570
- Agent factory is a static method that takes `AzureOpenAIClient`, `modelDeployment`, and `ITaskRepository`
@@ -272,10 +307,90 @@ To add a new safety layer:
272307
| `Infrastructure/Data/TaskDbContext.cs` | EF Core DbContext, entity configurations |
273308
| `Infrastructure/Repositories/TaskRepository.cs` | Repository pattern implementation |
274309

310+
## Package Management - Central Version Control
311+
312+
**CRITICAL**: This project uses **Central Package Management** (CPM) via `Directory.Packages.props`.
313+
314+
**How it works**:
315+
316+
- `Directory.Build.props` → Common project settings (target framework, nullable, code analysis)
317+
- `Directory.Packages.props` → Centralized NuGet package versions
318+
- Individual `.csproj` files → Package references WITHOUT version numbers
319+
320+
**Adding a new package**:
321+
322+
```powershell
323+
# 1. Add to Directory.Packages.props
324+
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
325+
326+
# 2. Reference in .csproj (NO version attribute)
327+
<PackageReference Include="Newtonsoft.Json" />
328+
```
329+
330+
**Key packages**:
331+
332+
- `Microsoft.Agents.AI.OpenAI` (1.0.0-preview) - Agentic AI Framework
333+
- `Azure.AI.OpenAI` (2.1.0) - Azure OpenAI SDK
334+
- `Azure.AI.ContentSafety` (1.0.0) - Content Safety SDK
335+
- `Microsoft.EntityFrameworkCore.SqlServer` (9.0.10)
336+
- `SonarAnalyzer.CSharp` (9.32.0) - Code quality analysis
337+
338+
**Why CPM?**: Ensures version consistency across all projects, prevents dependency conflicts, simplifies upgrades.
339+
340+
## Thread Persistence & Conversation State
341+
342+
**Architecture**: Conversations are persisted using `IThreadPersistenceService` to maintain context across HTTP requests.
343+
344+
**Flow**:
345+
346+
1. User sends message with optional `threadId`
347+
2. If `threadId` exists → deserialize thread state: `AgentThread.Deserialize(serializedState)`
348+
3. Agent processes message with full conversation history
349+
4. After response → serialize thread state: `thread.Serialize()`
350+
5. Save to persistence layer: `await _threadPersistence.SaveThreadAsync(threadId, serializedState)`
351+
352+
**Implementations**:
353+
354+
- **Development**: `InMemoryThreadPersistenceService` (ConcurrentDictionary, singleton)
355+
- **Production**: Implement with Redis/SQL Server (scoped/transient)
356+
357+
**Critical**: Thread state contains entire conversation history - must be serialized/deserialized for each request.
358+
359+
**Code example** (see `TaskAgentService.SendMessageAsync`):
360+
361+
```csharp
362+
// Load existing thread or create new
363+
string? serializedThread = await _threadPersistence.GetThreadAsync(threadId);
364+
AgentThread thread = string.IsNullOrEmpty(serializedThread)
365+
? await _agent.CreateThreadAsync()
366+
: AgentThread.Deserialize(serializedThread);
367+
368+
// Process message
369+
await thread.AddUserMessageAsync(message);
370+
await foreach (var response in thread.InvokeAsync(_agent)) { }
371+
372+
// Save updated thread
373+
await _threadPersistence.SaveThreadAsync(threadId, thread.Serialize());
374+
```
375+
376+
**Production considerations**:
377+
378+
- Thread state grows with conversation length
379+
- Consider TTL/cleanup strategies for old threads
380+
- Scoped lifetime for multi-server scenarios
381+
275382
## Testing Guidance
276383

277384
**Content Safety**: See `CONTENT_SAFETY.md` for 75+ test cases including prompt injections, harmful content, edge cases, and troubleshooting.
278385

279-
**AI Agent**: Test via web UI at `http://localhost:5000` or POST to `/api/chat` endpoint with `{"message": "your message"}`
386+
**AI Agent**: Test via web UI at `http://localhost:5000` or POST to `/api/chat` endpoint with `{"message": "your message", "threadId": "optional-thread-id"}`
280387

281388
**Database**: Auto-created on first run. To reset: `dotnet ef database drop --project TaskAgent.Infrastructure --startup-project TaskAgent.WebApp`
389+
390+
**Key Test Scenarios**:
391+
392+
1. Task creation with validation (title length, priority values)
393+
2. Business rule enforcement (can't reopen completed tasks)
394+
3. Thread persistence across multiple requests (same threadId)
395+
4. Content safety blocking (prompt injection, harmful content)
396+
5. Parallel safety checks performance (~200-400ms)

.github/git-commit-messages-instructions.md

Lines changed: 112 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,24 @@ These instructions guide GitHub Copilot in generating Git commit messages that a
9494
- "Simple, self-explanatory single-file changes"
9595
- "The title completely describes the change"
9696
- "Trivial fixes or updates (e.g., 'docs: fix typo in README')"
97-
- "Include a longer description of the changes, if necessary. Use complete sentences."
97+
- "**BODY FORMAT AND STYLE:**"
98+
- "Write in **past tense** (describe what was done, not what to do)"
99+
- "Examples: 'Added feature X', 'Implemented Y', 'Fixed Z', 'Updated configuration'"
100+
- "Use complete sentences with proper capitalization and punctuation"
101+
- "Wrap lines at 72 characters for readability"
102+
- "Separate paragraphs with blank lines for better structure"
103+
- "**LISTING MODIFIED FILES:**"
104+
- "For **2-10 files**: List files with brief description of changes"
105+
- "Format: 'Modified files (X):' or 'Affected files (X):' followed by bulleted list"
106+
- "Use `-` (hyphen) for bullet points, not ``"
107+
- "Example format: `- FileName.cs: Brief description of change`"
108+
- "File descriptions should use past tense (e.g., 'Added method', 'Updated logic')"
109+
- "For **>10 files**: Group by layer/component instead of listing all files"
110+
- "Example: 'This change spans multiple layers (15 files modified):'"
111+
- "Then list high-level changes by component/layer, not individual files"
112+
- "For **1 file**: Generally omit file listing (it's in the commit diff)"
98113
- "Explain the motivation for the change and how it differs from previous behavior."
99-
- "Wrap lines at 72 characters."
114+
- "For significant changes, include performance metrics, testing notes, or migration guidance."
100115
- **Footer (Optional):**
101116
- "Use the footer to reference issue trackers, breaking changes, or other metadata."
102117
- "**Breaking Changes:** Start with `BREAKING CHANGE: ` (or `BREAKING-CHANGE:`) followed by a description. Alternatively, append `!` after type/scope (e.g., `feat!:` or `feat(api)!:`)."
@@ -324,52 +339,84 @@ Fixes #156
324339
```
325340
feat(WebApp.Middleware): add prompt injection detection
326341
327-
Implement Azure Content Safety prompt shield to detect
342+
Implemented Azure Content Safety prompt shield to detect
328343
and block jailbreak attempts before reaching the AI agent.
329-
Returns 400 status with descriptive error message.
344+
Added 400 status response with descriptive error message.
330345
331-
Modified files:
332-
- ContentSafetyMiddleware.cs: Add prompt shield check
333-
- ContentSafetyService.cs: Implement shield API call
334-
- IContentSafetyService.cs: Add interface method
346+
Modified files (3):
347+
- ContentSafetyMiddleware.cs: Added prompt shield check
348+
- ContentSafetyService.cs: Implemented shield API call
349+
- IContentSafetyService.cs: Added interface method
335350
336351
Closes #42
337352
```
338353

339354
```
340355
refactor(Domain): extract task validation to factory method
341356
342-
Move validation logic from constructor to TaskItem.Create()
357+
Moved validation logic from constructor to TaskItem.Create()
343358
factory method following domain-driven design principles.
344-
Ensures all task creation goes through proper validation.
359+
This ensures all task creation goes through proper validation.
345360
346-
This change affects TaskItem entity and all places where
347-
tasks are created, but maintains the same validation behavior.
361+
Affected files (2):
362+
- TaskItem.cs: Extracted Create() factory method
363+
- TaskRepository.cs: Updated to use factory method
364+
365+
This change maintains the same validation behavior while
366+
improving code organization and testability.
348367
```
349368

350369
```
351370
perf(Infrastructure): add database indexes for task queries
352371
353-
Add composite index on Status, Priority, and CreatedAt columns
354-
to optimize filtering queries. Reduces query time by 75% for
355-
GetAllTasksAsync with multiple filters.
372+
Added composite index on Status, Priority, and CreatedAt
373+
columns to optimize filtering queries. Performance tests
374+
showed 75% reduction in query time for GetAllTasksAsync
375+
with multiple filters applied.
376+
377+
Modified files (2):
378+
- TaskDbContext.cs: Added index configuration
379+
- 20251018_AddTaskIndexes.cs: New EF migration
356380
357-
Modified:
358-
- TaskDbContext.cs: Add index configuration
359-
- New migration: 20251018_AddTaskIndexes.cs
381+
Refs: #89
382+
```
383+
384+
```
385+
feat(Application): implement task search and filtering
386+
387+
Added comprehensive search and filtering capabilities for
388+
tasks including full-text search, status filtering, priority
389+
filtering, and date range queries.
390+
391+
This change spans multiple layers (12 files modified):
392+
- Application layer: New DTOs, interfaces, and service methods
393+
- Infrastructure layer: Repository implementations and queries
394+
- WebApp layer: New API endpoints and request validators
395+
396+
Key changes:
397+
- Created SearchTasksDto with filter parameters
398+
- Implemented full-text search on Title and Description
399+
- Added composite indexes for performance
400+
- Created GET /api/tasks/search endpoint
401+
- Added pagination support (page size, page number)
402+
403+
Performance: Search queries execute in <100ms for 10k records.
404+
405+
Closes #45, #67, #89
360406
```
361407

362408
```
363409
docs: update architecture and setup documentation
364410
365-
Update README.md with new setup steps, add CONTENT_SAFETY.md
366-
with comprehensive testing guide, and update copilot
367-
instructions with latest conventions.
411+
Updated project documentation to reflect current architecture
412+
patterns and setup requirements. Added comprehensive content
413+
safety testing guide with 75+ test cases.
368414
369-
Modified files:
370-
- README.md: Add Azure OpenAI setup section
371-
- CONTENT_SAFETY.md: New file with 75+ test cases
372-
- .github/copilot-instructions.md: Update DI patterns
415+
Modified files (4):
416+
- README.md: Added Azure OpenAI setup section
417+
- CONTENT_SAFETY.md: New file with testing guide
418+
- .github/copilot-instructions.md: Updated DI patterns
419+
- .github/git-commit-messages-instructions.md: Added examples
373420
```
374421

375422
**Cross-Layer Examples:**
@@ -419,6 +466,19 @@ Modified files:
419466
- "Single file, simple change"
420467
- "Title is completely self-explanatory"
421468
- "Trivial updates (e.g., 'docs: fix typo')"
469+
- "**BODY WRITING STYLE - CRITICAL:**"
470+
- "**Header (title)**: Use IMPERATIVE PRESENT tense (e.g., 'add feature', 'fix bug', 'update config')"
471+
- "**Body**: Use PAST TENSE (e.g., 'Added feature', 'Fixed bug', 'Updated config')"
472+
- "Body describes what WAS done, header describes what the commit DOES"
473+
- "Use `-` (hyphen) for bullet points in body, NEVER `` or other symbols"
474+
- "File listings format:"
475+
- "2-10 files: List each file with hyphen. Example: `- FileName.cs: Added method`"
476+
- ">10 files: Group by layer/component, don't list all files individually"
477+
- "Example for many files:"
478+
- "❌ DON'T: List all 15 files individually (too verbose)"
479+
- "✅ DO: 'This change spans multiple layers (15 files modified):'"
480+
- "Then describe by component: 'Application layer: New DTOs and services'"
481+
- "Wrap lines at 72 characters for readability"
422482
- "**BREAKING CHANGES - Critical Decision Guide:**"
423483
- "Use `BREAKING CHANGE:` footer or `!` suffix when consumers MUST modify their code"
424484
- "**Ask yourself**: Would existing code that uses this API/endpoint/interface still work?"
@@ -511,11 +571,37 @@ Modified files:
511571
**Multi-File Changes - Body Guidelines:**
512572

513573
- **Include body if:**
514-
- 2+ files modified (list affected files/components)
574+
- 2+ files modified (describe changes and list files if ≤10)
515575
- Change spans multiple layers or scopes
516576
- Explanation needed for WHY (not just WHAT)
517577
- Breaking changes or migrations involved
518578
- **Body can be omitted if:**
519579
- Single file, straightforward change
520580
- Title like "docs: fix typo in README" is self-explanatory
521581
- Trivial formatting or style changes
582+
583+
**File Listing Best Practices:**
584+
585+
- **2-10 files modified:**
586+
- Include section: "Modified files (X):" or "Affected files (X):"
587+
- List each file with hyphen and brief description
588+
- Example: `- TaskService.cs: Added search method`
589+
- Use past tense for descriptions
590+
- **>10 files modified:**
591+
- DON'T list all files individually (commit becomes too long)
592+
- State total count: "This change spans multiple layers (15 files modified):"
593+
- Group changes by layer/component/category
594+
- Example: "Application layer: New DTOs, interfaces, and service methods"
595+
- Example: "Infrastructure layer: Repository implementations and queries"
596+
- Focus on WHAT changed in each component, not listing every file
597+
- **1 file modified:**
598+
- Generally omit file listing (obvious from commit diff)
599+
- Use body to explain WHY and HOW, not WHAT file
600+
601+
**Body Writing Style:**
602+
603+
- Header (title): Imperative present ("add feature", "fix bug")
604+
- Body: Past tense ("Added feature", "Implemented logic", "Fixed validation")
605+
- Bullet points: Use `-` (hyphen), not `` or other symbols
606+
- Line length: Wrap at 72 characters
607+
- Paragraphs: Separate with blank lines for readability

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,17 @@ TaskAgent.WebApp (UI, Controllers, AI Agent)
8181
**Key Components**:
8282

8383
- **Domain**: `TaskItem` entity with business rules, Status/Priority enums
84-
- **Application**: DTOs (using record types), `ITaskRepository`, 6 AI function tools
85-
- **Infrastructure**: `TaskDbContext`, `TaskRepository`, `ContentSafetyService` with HttpClientFactory
84+
- **Application**: DTOs (using record types), `ITaskRepository`, `IThreadPersistenceService`, 6 AI function tools
85+
- **Infrastructure**: `TaskDbContext`, `TaskRepository`, `ContentSafetyService` with HttpClientFactory, `InMemoryThreadPersistenceService`
8686
- **Presentation**: MVC controllers, Razor views, `TaskAgentService`, configuration validation extensions
8787

88+
**Conversation Persistence**:
89+
90+
- Thread state serialized/deserialized across requests using `AgentThread.Serialize()`
91+
- `IThreadPersistenceService` abstraction for storage flexibility
92+
- In-memory implementation for single-server deployments
93+
- Production: Use Redis/SQL for multi-server scenarios
94+
8895
---
8996

9097
## 🛠️ Tech Stack
@@ -208,8 +215,9 @@ Agent provides 1-2 smart suggestions after each operation:
208215
TaskAgentWeb/
209216
├── TaskAgent.Domain/ # Entities, Enums
210217
├── TaskAgent.Application/ # DTOs (record types), Interfaces, Functions
218+
│ └── Interfaces/ # ITaskRepository, IThreadPersistenceService
211219
├── TaskAgent.Infrastructure/ # DbContext, Repositories, Azure Services
212-
│ ├── Services/ # ContentSafetyService (HttpClientFactory)
220+
│ ├── Services/ # ContentSafetyService, InMemoryThreadPersistenceService
213221
│ ├── Models/ # ContentSafetyConfig, PromptShieldResponse
214222
│ └── DependencyInjection.cs # Named HttpClient registration
215223
└── TaskAgent.WebApp/ # Controllers, Views, Services

0 commit comments

Comments
 (0)