fix: pinned chat panel layout, CommonMark parsing, and CSS animation - #7
Conversation
…hOrderedMarker Update startsWithOrderedMarker() to reject markers without whitespace after the delimiter (e.g., '1.Foo'), per CommonMark spec. The shared scanAt() method remains unchanged to preserve InlineListParser behavior for LLM-generated inline lists.
- Fix ThinkingIndicator CSS animation name mismatch (icon-sparkle/sparkle-glow) - Improve LearnView chat panel layout with pinned frame styling - Add whitespace requirement after markers in OrderedMarkerScanner - Add null safety checks in ExceptionResponseBuilder for headers/body
Fix CSS class mismatch where icon-sparkle referenced generate-glow animation. Renamed to sparkle-glow for consistency with the icon class name.
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughAdds frontend layout and scrolling fixes, error handling for lesson citations, a renamed animation, CommonMark-accurate ordered-list detection, stricter null checks in exception builders, multi-turn prompt inclusion, a session-validation endpoint and response record, and tests for ChatMemory behavior. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client
participant Controller as GuidedLearningController
participant Memory as ChatMemory
participant Builder as PromptBuilder
participant OpenAI as OpenAIStream
Client->>Controller: POST /guided-learning (user message)
Controller->>Memory: loadHistory(sessionId)
Controller->>Builder: buildGuidedPromptWithContext(history, latestUserMessage)
Controller->>Memory: addUserMessage(sessionId, latestUserMessage)
Controller->>OpenAI: start streaming with prompt
OpenAI-->>Controller: stream tokens/results
Controller-->>Client: stream SSE/chunks to client
Controller->>Memory: addAssistantMessage(sessionId, assistantFinal)
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR tightens error/edge-case handling across backend and frontend, and refines markdown ordered-marker detection and UI behavior.
Changes:
- Add null-safety guards when building exception details for WebClient/OpenAI errors.
- Refine ordered-list marker detection to enforce CommonMark-style whitespace after delimiters.
- Adjust frontend UI/UX: lesson citations promise rejection handling, chat panel layout/styling, and a keyframes rename for the thinking indicator.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/main/java/com/williamcallahan/javachat/web/ExceptionResponseBuilder.java | Prevent potential NPEs when formatting exception response bodies/headers. |
src/main/java/com/williamcallahan/javachat/service/markdown/OrderedMarkerScanner.java | Update ordered-marker detection behavior/documentation toward CommonMark compliance. |
frontend/src/lib/components/ThinkingIndicator.svelte | Rename sparkle glow keyframes and update the animation reference accordingly. |
frontend/src/lib/components/LearnView.svelte | Add citations .catch handling and update chat/lesson layout CSS for pinned scrolling behavior and responsiveness. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@src/main/java/com/williamcallahan/javachat/service/markdown/OrderedMarkerScanner.java`:
- Around line 73-80: In OrderedMarkerScanner, rename the loop index `i` to a
descriptive name (e.g., `cursor`) in the for loop inside the method that
iterates trimmedLine so replace uses of `i` with `cursor` (update the for
header, the char retrieval `trimmedLine.charAt(...)`, and `posAfterDelimiter =
...`) and ensure any other references in the method are updated accordingly to
avoid the banned generic identifier.
Uh oh!
There was an error while loading. Please reload this page.
The loop variable 'i' violates naming rule ND2 which bans single-letter identifiers except in trivial contexts. Rename to 'cursor' to match the naming convention used elsewhere in OrderedMarkerScanner (e.g., lines 161, 178) and improve code readability.
…onversations The frontend displays full conversation history (user + assistant messages), but buildPromptFromMessages() was filtering out AssistantMessage instances, causing the LLM to receive only user messages. This broke multi-turn conversations since the AI had no memory of its previous responses, despite the user seeing them. Additionally, GuidedLearningController was adding the user message to memory BEFORE loading history, causing the message to appear twice in the prompt. - Include AssistantMessage in buildPromptFromMessages() with "Assistant:" prefix - Add AssistantMessage import to ChatService - Fix history loading order in GuidedLearningController (load before add) - Add Javadoc explaining the context agreement requirement
Frontends lose session context after server restarts because chat memory is in-memory only. This adds a validation endpoint allowing frontends to detect session drift by comparing their local message count against the server's turn count, enabling graceful recovery or user notification. - Add GET /api/chat/session/validate endpoint returning turn count and exists flag - Create SessionValidationResponse record for structured API response - Add comprehensive ChatMemoryServiceTest covering message storage, ordering, session isolation, and snapshot safety
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/main/java/com/williamcallahan/javachat/web/ChatController.java`:
- Around line 285-305: The null sessionId passed into the bad-request
SessionValidationResponse should be replaced with a safe placeholder (e.g. empty
string) to avoid returning null in JSON; update the validateSession method so
the ResponseEntity.badRequest() builds new SessionValidationResponse with "" (or
a chosen placeholder) instead of sessionId while keeping the rest of the fields
the same; ensure this change references the validateSession(...) endpoint and
the SessionValidationResponse constructor so the response object accepts the
non-null placeholder.
🧹 Nitpick comments (1)
src/main/java/com/williamcallahan/javachat/web/SessionValidationResponse.java (1)
12-17: Clean record design! 📝This is a well-structured DTO with clear, domain-specific field names. The Javadoc nicely explains the purpose of each field.
One small thought: per coding guidelines, domain value types benefit from constructor validation. You could add a compact constructor to guard against null
sessionId:💡 Optional: Add constructor validation
public record SessionValidationResponse( String sessionId, int turnCount, boolean exists, String message) { + public SessionValidationResponse {+ if (sessionId == null) {+ throw new IllegalArgumentException("sessionId cannot be null");+ }+ } }That said, since the controller validates
sessionIdbefore constructing this response, this is a nice-to-have rather than essential.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
Improves the Learn view chat panel UX with a pinned frame layout, fixes CommonMark-compliant ordered list parsing, and resolves CSS animation issues.
Changes by Category
UI/UX Improvements
Bug Fixes
generate-glowkeyframes tosparkle-glowto match.icon-sparkleclass referenceresponseBodyandheadersbefore calling methods on them.catch()handler on citation fetch promiseSpec Compliance
startsWithOrderedMarker()now rejects markers without whitespace after delimiter (e.g., "1.Foo" rejected, "1. Foo" accepted)Technical Details
min-height: 0for proper overflow scrollingFiles Changed
LearnView.svelteThinkingIndicator.svelteOrderedMarkerScanner.javaExceptionResponseBuilder.java