Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR introduces a configurable Support menu (Latest Features + Send Feedback) for signed-in users and hardens the chat finalization pipeline by sanitizing non-finite numeric values (NaN/±Infinity) before persistence/response emission to avoid Cosmos DB invalid-JSON failures.
Changes:
- Added Support menu configuration, templates, JS, routes, and functional/UI coverage for sidebar/top-nav visibility and latest-features image modal previews.
- Centralized post-stream JSON sanitization via
make_json_serializable()and applied it across chat finalization, artifacts, and terminal SSE/JSON payloads. - Updated versioning and added fix/feature documentation for Support menu and chat post-stream sanitization.
Reviewed changes
Copilot reviewed 29 out of 45 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| ui_tests/test_support_menu_sidebar_visibility.py | Adds UI regression test for Support section visibility in left sidebar when enabled. |
| ui_tests/test_support_latest_features_image_modal.py | Adds UI regression test for Latest Features image modal behavior. |
| ui_tests/test_single_app_template_json_bootstrap_render.py | Extends bootstrap render test to assert new Latest Features selectors on admin settings page. |
| functional_tests/test_support_menu_user_feature.py | Adds functional “marker” tests to validate Support menu plumbing across templates/routes/config. |
| functional_tests/test_chat_post_stream_json_sanitization.py | Adds regression tests ensuring non-finite values are sanitized pre-persistence/response. |
| functional_tests/test_admin_latest_features_tab.py | Updates expected Latest Features tab markers and assets for new cards/screenshots. |
| docs/explanation/fixes/SUPPORT_MENU_SIDEBAR_VISIBILITY_FIX.md | Documents Support menu sidebar visibility fix and validation. |
| docs/explanation/fixes/SUPPORT_LATEST_FEATURE_IMAGES_FIX.md | Documents user Latest Features image modal parity and catalog/image updates. |
| docs/explanation/fixes/CHAT_STREAM_POST_FINALIZATION_JSON_SANITIZATION_FIX.md | Documents the NaN/Infinity sanitization fix and impact. |
| docs/explanation/features/LATEST_FEATURES_ADMIN_TAB.md | Updates admin Latest Features documentation for new cards/screenshots. |
| application/single_app/templates/support_send_feedback.html | Adds user-facing Send Feedback page/template. |
| application/single_app/templates/latest_features.html | Adds user-facing Latest Features page with gallery + modal + inline styling. |
| application/single_app/templates/admin_settings.html | Adds Support menu admin configuration UI + expands Latest Features tab content. |
| application/single_app/templates/_top_nav.html | Adds Support dropdown to top navigation when enabled and destinations available. |
| application/single_app/templates/_sidebar_short_nav.html | Adds Support section to compact sidebar and collapsible behavior. |
| application/single_app/templates/_sidebar_nav.html | Adds Support section to left sidebar and expands Latest Features nav entries. |
| application/single_app/support_menu_config.py | Introduces shared Support latest-features catalog + visibility normalization helpers. |
| application/single_app/static/js/support/support_feedback.js | Adds client logic to request server draft metadata + open mailto. |
| application/single_app/static/js/support/latest_features.js | Adds Bootstrap modal wiring for user Latest Features thumbnails. |
| application/single_app/static/js/admin/admin_settings.js | Adds admin-side DOM toggling for Support menu settings sections. |
| application/single_app/route_frontend_support.py | Adds frontend routes for Support destinations (Latest Features, Send Feedback). |
| application/single_app/route_frontend_admin_settings.py | Persists/normalizes Support settings and passes catalog to template. |
| application/single_app/route_backend_settings.py | Adds backend endpoint to log/prepare support feedback email draft metadata. |
| application/single_app/route_backend_chats.py | Replaces local serializers with shared make_json_serializable() and sanitizes outputs. |
| application/single_app/functions_settings.py | Adds Support defaults + sanitizes user-visible settings payload (hiding recipient email). |
| application/single_app/functions_message_artifacts.py | Adds NaN/Infinity normalization + strict JSON dump for artifact payloads. |
| application/single_app/functions_activity_logging.py | Adds activity logging for user-initiated support feedback mailto drafts. |
| application/single_app/config.py | Bumps app VERSION to 0.240.063. |
| application/single_app/app.py | Registers new Support frontend routes. |
Comments suppressed due to low confidence (1)
ui_tests/test_support_latest_features_image_modal.py:1
- This assertion is effectively a no-op: it computes the current count and then expects the locator to have that same count. It also won’t wait for cards to appear because
.count()is evaluated immediately. Make the assertion meaningful (e.g., assert count > 0, orexpect(locator.first).to_be_visible(), or use a known minimum count) so the test fails when the page renders no feature cards.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 34 out of 50 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
functional_tests/test_chat_post_stream_json_sanitization.py:1
- This test hard-codes the application config VERSION to 0.240.063, but
application/single_app/config.pyis updated to 0.240.066 in this PR. This will fail as soon as the app version moves beyond the fix version. Consider asserting only the fix doc version (since that’s what this test is about), or relaxing the config assertion (e.g., removing it, or asserting the config version is >= the fix version if you have a version-compare helper).
| {% set support_menu_role_allowed = 'Admin' in session['user']['roles'] or 'User' in session['user']['roles'] %} | ||
| {% if support_menu_role_allowed and app_settings.enable_support_menu %} | ||
| {% set show_support_latest_features = app_settings.enable_support_latest_features and app_settings.support_latest_features_has_visible_items %} | ||
| {% set show_support_send_feedback = app_settings.enable_support_send_feedback and app_settings.support_feedback_recipient_configured %} |
There was a problem hiding this comment.
Unlike the sidebar templates, this top-nav block directly indexes session['user']['roles']. On pages rendered without a populated session['user'] (or where roles is missing/non-list), Jinja will raise and break page rendering. Align this with _sidebar_nav.html / _sidebar_short_nav.html by using session.get('user'), .get('roles'), and a safe role-membership check.
| const result = await response.json(); | ||
| if (!response.ok) { | ||
| throw new Error(result.error || 'Unable to prepare the feedback email draft.'); | ||
| } | ||
|
|
There was a problem hiding this comment.
Calling response.json() unconditionally can throw when the backend returns a non-JSON response (proxies, HTML error pages, auth middleware, etc.), which then surfaces a confusing parse error message to the user. Prefer parsing defensively (e.g., check Content-Type before .json(), or wrap JSON parsing in a try/catch and fall back to response.text() / a generic error message).
| const result = await response.json(); | |
| if (!response.ok) { | |
| throw new Error(result.error || 'Unable to prepare the feedback email draft.'); | |
| } | |
| const contentType = response.headers.get('content-type') || ''; | |
| const isJsonResponse = contentType.includes('application/json'); | |
| let result = null; | |
| let responseText = ''; | |
| if (isJsonResponse) { | |
| result = await response.json(); | |
| } else { | |
| responseText = await response.text(); | |
| } | |
| if (!response.ok) { | |
| throw new Error( | |
| result?.error || | |
| responseText || | |
| 'Unable to prepare the feedback email draft.' | |
| ); | |
| } | |
| if (!result) { | |
| throw new Error('Unable to prepare the feedback email draft.'); | |
| } |
| except (TypeError, ValueError): | ||
| serializable = make_json_serializable(citation) | ||
| if not isinstance(serializable, dict): | ||
| serializable = {'value': str(citation)} |
There was a problem hiding this comment.
When a citation sanitizes to a non-dict (e.g., list/primitive), the code currently discards the sanitized structure and replaces it with {'value': str(citation)}. This loses potentially useful structured data even though it’s now JSON-safe. Consider preserving the sanitized value (e.g., {'value': serializable}) so downstream telemetry/debugging can still inspect the original shape.
| serializable = {'value': str(citation)} | |
| serializable = {'value': serializable} |
Support Menu and User-Facing Latest Features
support_menu_config.py,route_frontend_support.py,latest_features.html,support_send_feedback.html,admin_settings.html,test_support_menu_user_feature.py, support menu configuration and user-facing latest features)Streaming Chat Post-Finalization JSON Sanitization
Stream interruptedwarning during final persistence.functions_message_artifacts.py,route_backend_chats.py,test_chat_post_stream_json_sanitization.py, post-stream citation sanitization)