Repository navigation
fix(chat): grounding and web chat reply fixes (#470, #471) - #472
Conversation
Grounding metadata overlapped adjacent chat bubbles on native because WebViews in GiftedChat's inverted list paint outside their bounds. Clip the widget, auto-size to content, and disable FlatList subview clipping. Co-authored-by: Cursor <cursoragent@cursor.com>
Sanitize script tags and inline event handlers before enabling JS for height measurement, align web iframe sanitization, and type list props with FlatListProps instead of an assertion. Co-authored-by: Cursor <cursoragent@cursor.com>
fix(grounding): contain search suggestions WebView on iOS and Android
Co-authored-by: Cursor <cursoragent@cursor.com>
Firebase web was sending null for omitted optional generateReply fields, breaking web chat. Grounding search suggestions now use shadow DOM with probe-width horizontal scrolling and natural height on web. Co-authored-by: Cursor <cursoragent@cursor.com>
Harden shadow DOM HTML sanitization with an allowlist, guard layout sync on unmount, preserve MessageText left/right styling, and skip empty-response retries for deterministic Gemini finish reasons. Co-authored-by: Cursor <cursoragent@cursor.com>
fix(web): restore chat replies and grounding widget layout
|
Warning Review limit reached
More reviews will be available in 28 minutes and 14 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (11)
Comment |
There was a problem hiding this comment.
Pull request overview
Promotes fixes from staging to main to stabilize grounding (Google Search Suggestions widget) rendering across native + web, harden HTML sanitization, and address web chat 400s / empty-model-response handling in generateReply.
Changes:
- Added native + web grounding HTML sanitizers, including a shadow-DOM render path on web with measurement utilities for horizontal scrolling and natural height.
- Updated chat UI rendering (bubble constraints, message wrapping, grounding container styles) and native WebView grounding sizing/containment behavior.
- Hardened callable payload construction and backend parsing (
unsyncedHistory: null), plus introduced a one-time retry for empty Gemini responses with added tests.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/sanitizeGroundingHtml.ts | Adds native-focused regex sanitization (strip scripts/inline handlers + unsafe links). |
| src/utils/groundingShadowContent.ts | Implements web shadow-DOM sanitizer, mounting, and layout/scroll measurement helpers. |
| src/utils/tests/sanitizeGroundingHtml.test.ts | Unit tests for native sanitization helpers. |
| src/utils/tests/groundingShadowContent.test.ts | Unit tests for shadow DOM sanitization + layout/scroll helpers. |
| src/services/chatReplyService.ts | Omits undefined optional callable fields to avoid Firebase web encoding them as null. |
| src/components/GroundingHtml.web.tsx | Switches web grounding rendering to shadow DOM + horizontal scrollport with measurement. |
| src/components/GroundingHtml.tsx | Updates native grounding rendering to sanitize + auto-measure WebView height. |
| src/components/ChatView.tsx | Adjusts bubble/layout constraints for web grounding and disables list clipping to prevent native WebView overdraw. |
| package-lock.json | Lockfile metadata change (fsevents dev flag removal). |
| functions/src/generateReply.ts | Adds empty-response retry logic + treats unsyncedHistory: null as absent. |
| functions/src/generateReply.test.ts | Adds coverage for unsyncedHistory: null behavior. |
| tests/chatReplyService.test.ts | Adds coverage ensuring undefined optional callable fields are omitted. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Use iterative replaceUntilStable for script and event-handler stripping, and allow whitespace before script closing tags. Co-authored-by: Cursor <cursoragent@cursor.com>
/fix-pr follow-upCommit: Review resolution
Verification
|
Skip retry when empty responses have non-retryable finish reasons, remove script/style entirely in shadow sanitizer, fix svg viewBox allowlist casing, and limit removeClippedSubviews to native only. Co-authored-by: Cursor <cursoragent@cursor.com>
/fix-pr follow-upCommit: Review resolution
Verification
|
Allow arbitrary non-> characters after </script so closers like </script\t\n bar> are stripped per CodeQL bad-tag-filter. Co-authored-by: Cursor <cursoragent@cursor.com>
/fix-pr follow-upCommit: Review resolution
Verification
|
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Kurt VanDusen <info@equationalapplications.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Kurt VanDusen <info@equationalapplications.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Kurt VanDusen <info@equationalapplications.com>
| /** Defense-in-depth sanitization before rendering grounding HTML on native WebViews. */ | ||
| export function sanitizeGroundingHtmlForNative(html: string): string { | ||
| return sanitizeGroundingHtmlLinksRegex(stripExecutableGroundingMarkup(html)) | ||
| } |
| function isAllowedGroundingAttribute(tagName: string, attributeName: string): boolean { | ||
| const lowerName = attributeName.toLowerCase() | ||
| if (lowerName.startsWith('on') || lowerName.startsWith('data-') || lowerName.startsWith('aria-')) { | ||
| return lowerName.startsWith('aria-') || lowerName.startsWith('data-') | ||
| } | ||
| if (GROUNDING_GLOBAL_ALLOWED_ATTRS.has(lowerName)) { | ||
| return true | ||
| } | ||
| return GROUNDING_TAG_ALLOWED_ATTRS[tagName]?.has(lowerName) ?? false | ||
| } |
| useEffect(() => { | ||
| const scrollEl = scrollRef.current | ||
| if (!scrollEl) { | ||
| return | ||
| } | ||
|
|
||
| const onWheel = (event: WheelEvent) => { | ||
| if (applyHorizontalWheelToScrollport(event, scrollEl)) { | ||
| event.preventDefault() | ||
| event.stopPropagation() | ||
| } | ||
| } | ||
|
|
||
| scrollEl.addEventListener('wheel', onWheel, { capture: true, passive: false }) | ||
| return () => scrollEl.removeEventListener('wheel', onWheel, { capture: true }) | ||
| }, [contentWidth]) |
| function isAllowedGroundingAttribute(tagName: string, attributeName: string): boolean { | ||
| const lowerName = attributeName.toLowerCase() | ||
| if (lowerName.startsWith('on') || lowerName.startsWith('data-') || lowerName.startsWith('aria-')) { | ||
| return lowerName.startsWith('aria-') || lowerName.startsWith('data-') | ||
| } | ||
| if (GROUNDING_GLOBAL_ALLOWED_ATTRS.has(lowerName)) { | ||
| return true | ||
| } | ||
| return GROUNDING_TAG_ALLOWED_ATTRS[tagName]?.has(lowerName) ?? false | ||
| } |
Description
Promotes staging to main with grounding metadata and web chat fixes from #470 and #471.
generateReply, restores grounding widget layout on web (shadow DOM, horizontal scroll, natural height), and hardens sanitization from review feedback.Type of Change
Related Issue
Fixes #
Changes Made
Native grounding (#470)
GroundingHtmlWebView in a clipped container withopacity: 0.99to prevent overlap with sibling list rowsremoveClippedSubviewson GiftedChat's message list to avoid FlatList clipping WebViews incorrectlyoverflow: 'hidden'on the grounding container inChatViewWeb chat and grounding (#471)
generateChatReplypayload so Firebase web does not encode them asnullnullunsyncedHistoryas absent ingenerateReplyparsingmaxWidth: 80%) and disable bubble press so scroll gestures are not swallowedTests
groundingShadowContent.test.ts,sanitizeGroundingHtml.test.tschatReplyService.test.ts,generateReply.test.tsTesting
Platforms Tested
Test Steps
Native (#470)
Web (#471)
unsyncedHistory400)npm run test(grounding andgenerateReplycoverage)Screenshots
Before
Native: grounding metadata overlapped adjacent bubbles and was vertically compressed. Web: wide chips clipped with no horizontal scroll; web chat intermittently failing with 400s.
After
Native: widget contained within bubble with readable chips. Web: horizontal scroll works, widget height fits content, chat replies succeed.
Checklist
Additional Notes
renderedContentMade with Cursor