## 1. Markdown Service - [x] 1.1 Add Markdig NuGet package to ChatAgent.Client project - [x] 1.2 Create MarkdownService class with a ConfigureMarkdigPipeline method using AdvancedExtensions (GFM tables, task lists, pipe tables) - [x] 1.3 Add ConvertToHtml method that takes a markdown string and returns sanitized HTML - [x] 1.4 Implement HTML sanitization via tag/attribute allowlist (p, h1-h6, strong, em, code, pre, ul, ol, li, a[href], table, thead, tbody, tr, th, td, br, blockquote) - [x] 1.5 Register MarkdownService as singleton in Program.cs ## 2. Chat Component Integration - [x] 2.1 Inject MarkdownService into Chat.razor - [x] 2.2 For assistant messages, replace `@message.Content` with `@((MarkupString)MarkdownService.ConvertToHtml(message.Content))` - [x] 2.3 Keep user messages rendering as plain text via `@message.Content` - [x] 2.4 Verify streaming still works — markdown re-renders as tokens arrive ## 3. CSS Styling - [x] 3.1 Add CSS for rendered markdown inside assistant bubbles: code blocks (background, padding, border-radius, overflow-x auto), inline code (background, padding), paragraphs (margin control), lists (indentation), tables (borders, header styling), blockquotes (left border, padding), links (color, underline) - [x] 3.2 Ensure code blocks do not overflow bubble width — add horizontal scroll - [x] 3.3 Ensure last paragraph/element in bubble has no bottom margin (tight fit) ## 4. Testing - [x] 4.1 Add unit tests for MarkdownService: bold/italic, code blocks, lists, headings, tables, links - [x] 4.2 Add sanitization tests: script tags stripped, event handlers stripped, safe tags preserved - [x] 4.3 Manual test: send a message asking LLM to respond with markdown formatting and verify rendering