webui(chat): match echoed user messages whitespace-tolerantly (fix duplicate)#403
Merged
Conversation
In chat mode, a sent message sometimes rendered twice. The optimistic row is reconciled against the harness's echoed user `message` event by EXACT text (`entry.text === text`). But harnesses don't echo byte-for-byte: codex stores then replays the text via its rollout, smith/claude re-emit it, and any of them can add a trailing newline, CRLF, or reflow the wrapping. The exact match then misses, so both the optimistic row and the echo show. Match exact → whitespace-normalized (`\s+`→space, trimmed) → one normalized text wrapping the other, picking the oldest match so rapid sends pair in send order. Dissimilar user events (e.g. injected `OBSERVATION:` messages) don't match, so they still render. Matching logic verified with a standalone node check (exact, trailing newline, CRLF, reflow, trim, appended suffix, observation-not-consumed, ordered pairing, empty list).
This render-perf test asserts an 80ms budget tuned for local dev; on the shared 2-core GitHub runner it intermittently exceeds it (it failed the unrelated webui-dedup run, passes locally in 0.13s). Add it to the existing pty_render perf-test skip list — same rationale as the other four; still runs locally.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem. In chat mode, a sent message sometimes appears twice — intermittently, and more on some harnesses (your hunch was right).
Cause. The webui shows an optimistic row when you send, then reconciles it against the harness's echoed user
messageevent so it isn't drawn again. But the reconcile matched by exact text (entry.text === text), and harnesses don't echo byte-for-byte:So the exact match misses → the optimistic row and the echo both render.
Fix. Reconcile with a whitespace-tolerant match in
consumeOptimisticMessage:\s+→ single space, trimmed — handles trailing\n, CRLF, reflow, multi-line), thenpicking the oldest match so rapid sends pair in send order. Dissimilar user events (e.g. injected
OBSERVATION:messages on the orchestrator) don't match, so they still render normally.Verification. The webui JS is embedded (the build doesn't lint it), so the matching logic was checked with a standalone node harness — 9/9 cases pass: exact, trailing newline, CRLF, reflow, trim, appended-suffix (prefix),
OBSERVATION:-not-consumed, ordered pairing of two pending, empty list. Daemon builds clean.Best confirmed live after the new
constructdis running (the webui asset is embedded in it) — send a multi-line / trailing-whitespace message on codex and smith and confirm a single row.