fix(ui): stabilize WebChat final reload reconciliation#72325
fix(ui): stabilize WebChat final reload reconciliation#72325vincentkoc merged 3 commits intomainfrom
Conversation
Greptile SummaryThis PR fixes the WebChat final-event history reconciliation race by teaching Confidence Score: 4/5Safe to merge; changes are narrow, well-tested, and address a documented race condition without touching unrelated code paths. No P0/P1 findings. One P2 note about the SILENT_REPLY_PATTERN regex being case-sensitive (potential miss for lowercase/mixed-case sentinel variants). Logic is consistent across all reviewed edge cases. chat-event-reload.ts — verify SILENT_REPLY_PATTERN case sensitivity is intentional. Prompt To Fix All With AIThis is a comment left during a code review.
Path: ui/src/ui/chat-event-reload.ts
Line: 5
Comment:
**Case-sensitive sentinel may silently miss variants**
`SILENT_REPLY_PATTERN` only matches the exact uppercase string `NO_REPLY`. If the backend ever emits `no_reply`, `No_Reply`, or `NO_REPLY ` with a trailing newline inside the content block, `hasRenderableAssistantFinalMessage` would return `true`, suppressing the history reload and leaving the chat in a stale state. If the sentinel is contractually uppercase-only this is fine, but it is worth an explicit comment or a case-insensitive flag (`/^\s*NO_REPLY\s*$/i`) to make the intent clear.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(ui): stabilize WebChat final reload ..." | Re-trigger Greptile |
|
Thanks for picking this up and the kind credit! Appreciate you driving this forward systematically. |
b5bad4c to
0203dad
Compare
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🔵 Internal control reply tokens (ANNOUNCE_SKIP/REPLY_SKIP/no_reply) treated as renderable assistant text in UI
DescriptionThe UI logic that decides whether to reload chat history on a However, the backend defines multiple internal control reply tokens (
Impact:
Vulnerable code: const SILENT_REPLY_PATTERN = /^\s*NO_REPLY\s*$/;
...
return typeof text === "string" && text.trim() !== "" && !SILENT_REPLY_PATTERN.test(text);Only RecommendationTreat all backend-suppressed control tokens as non-renderable in the UI. Options:
const SUPPRESSED_CONTROL_TOKENS = ["NO_REPLY", "ANNOUNCE_SKIP", "REPLY_SKIP"] as const;
const SILENT_REPLY_PATTERN = new RegExp(`^\\s*(?:${SUPPRESSED_CONTROL_TOKENS.join("|")})\\s*$`, "i");
Also consider applying the same suppression in chat history rendering ( Analyzed PR: #72325 at commit Last updated on: 2026-04-27T19:51:38Z |
0203dad to
c362014
Compare
|
ProjectClownfish follow-up pushed: c362014 Fix:
Blacksmith validation:
|
c362014 to
97aba96
Compare
|
Rebased again onto current main after unrelated CI noise: 97aba96 No conflict resolution was needed on the final rebase; branch diff is still the same UI/WebChat surface. Prior Blacksmith validation remains scoped to this diff:
|
* fix(ui): stabilize WebChat final reload reconciliation * fix(clownfish): address review for ghcrawl-165991-agentic-merge (1) * fix(ui): keep plain control-token text visible
* fix(ui): stabilize WebChat final reload reconciliation * fix(clownfish): address review for ghcrawl-165991-agentic-merge (1) * fix(ui): keep plain control-token text visible
Summary
Fixes the remaining WebChat race tracked by #66875 after the active-send flicker fix from #66997. This should keep optimistic user messages stable while also preventing assistant final/streaming output from splitting into duplicate bubbles or disappearing during deferred history reconciliation.
Credit
This follows the root-cause reports from @BiznessFish in #66875/#66274, the merged active-send fix from @scotthuang in #66997, and the broader attempted follow-up from @hansolo949 in #67037. The replacement patch should preserve those contributions while keeping the implementation narrow and addressing the dropped/deferred reload concerns raised in automated review.
Validation
pnpm -s vitest run ui/src/ui/app-gateway.node.test.ts ui/src/ui/app-gateway.sessions.node.test.ts ui/src/ui/chat-event-reload.test.ts ui/src/ui/controllers/chat.test.tspnpm check:changedNotes
Keep this scoped to Control UI/WebChat event reconciliation. Do not change provider behavior, security boundaries, or unrelated history pagination.
ProjectClownfish replacement details: