V2: show the configured web search and AI notices - #1383
Merged
Paul Lizer (paullizer) merged 1 commit intoSep 2, 2026
Merged
Conversation
Two notices an administrator configures appeared in the classic chat page but never in V2, so anyone who switched interfaces stopped seeing them -- including the warning that a message is about to leave the tenant. Both reach the classic page through Jinja context, which the SPA cannot read, and neither is derivable from what /api/v2/bootstrap already carried. The AI notice's version hash is a SHA-256 of its message and frequency, and whether the caller's dismissal still applies depends on a stored, server-timestamped record; the web search notice additionally requires web_search_consent_accepted, which does not start with enable_ and so never reached the feature flags. Bootstrap therefore gains a notices block built from the same functions_ai_notice helpers the classic page uses, rather than a second implementation of the hash. Dismissals go where they can survive long enough: every_session stays in session storage, daily and once are written to /api/user/settings, and non_dismissible renders no control. The notice hides only after the write lands, so it cannot claim a dismissal that never happened. The session keys are the ones the classic client already writes, because a dismissal is a statement about the person, not about which interface they were looking at. V2's hardcoded "AI responses can be inaccurate" line is removed. It was not the administrator's wording, could not be turned off or dismissed, and appeared even where different text had been configured. When the AI notice is disabled V2 now shows nothing there, matching the classic interface. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
that referenced
this pull request
Sep 2, 2026
The base moved on twice while this was open: PR #1383 (web search and AI notices) and PR #1386 (inline image proposals). Both conflicts were version bookkeeping rather than code -- chatStore.ts auto-merged, and the two branches touch different parts of it. VERSION goes to 0.261.030. 0.261.028 was taken by the notices work and 0.261.029 by the image proposals, so this claims the next free number rather than reusing one; the mermaid branch is taking 0.261.031. The release note entry moves to a new 0.261.030 section above both of theirs, which are left intact, and the feature doc keeps both its testing-table rows. Verified after resolving: no leftover markers, the feature doc differs from the base only by additions, the full V2 suite (24 Python files plus the inline image proposal runtime checks) passes, both docs tests pass, and the bundle builds against the merged dependencies. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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
The classic chat page renders two administrator-configured notices around the composer. V2 rendered neither, so anyone who switched interfaces silently stopped seeing them — including the notice warning that their message is about to leave the tenant.
Instead, V2 ended its composer with a hardcoded line of its own:
That is not the same thing. It is not the administrator's wording, it cannot be turned off, it cannot be dismissed, and it appeared even for organisations that had deliberately configured different text.
Why it needed a server-side change
Both notices reach the classic page through Jinja template context, which a SPA cannot read — and neither was derivable from what
/api/v2/bootstrapalready carried:hashis a SHA-256 of its message and frequency. It is what invalidates stored dismissals when an administrator edits the wording, and whether the caller's dismissal still applies depends on a stored, server-timestamped record and a date window.web_search_consent_accepted, which does not start withenable_and so was never forwarded by_build_feature_flags. That is why it could not live incomposerGating.ts.So bootstrap gains a
noticesblock built from the samefunctions_ai_noticehelpers the classic page uses.route_backend_v2.pydeliberately does not hash anything itself, and a test asserts that — a second implementation of the hash would let the two interfaces disagree about whether an edited notice should reappear for someone who had dismissed the previous wording.Behaviour
The web search notice sits above the input and appears only while the Web toggle is armed — a banner that is always present stops being read, and the thing it warns about only happens when web search is on. Turning web search off hides it without consuming the dismissal.
The AI notice sits below the composer. Where a dismissal is stored depends on how long it has to last:
non_dismissibleevery_sessionsessionStoragedaily,once/api/user/settings→aiNoticeDismissalThe notice hides only after the write lands. Hiding first would tell a user the notice is gone for the day when it may be back on the next load. A failed write raises a toast rather than looking like a dead button.
daily/oncego through a dedicateddismissAiNotice()helper rather than the debounceduserSettingsStore: that store rolls failures back silently into a preference cache, but the route replaces the posted value with its own timestamped record, so the cached value would never match what was stored.Session keys are shared with the classic interface (
webSearchNoticeDismissed,simplechat.aiNoticeDismissal.<hash>) rather than namespaced the wayv2RailCollapsedis. A dismissal is a statement about the person, not about which interface they happened to be looking at; namespacing would make a just-dismissed notice reappear on switching interfaces in the same tab.sessionStoragethrows rather than returningnullin some privacy modes, so reads fail closed and writes report failure.The hardcoded "AI responses can be inaccurate. Verify important information." line is removed. When the AI notice is disabled, V2 now shows nothing there, matching the classic interface — an organisation that turned the notice off did so on purpose. To get a line back, enable it under Admin Settings → Notices & Agreements → Chat AI Notice. Flagged in the release notes.
Two bugs caught while building this
white-space: pre-line); the first pass collapsed them. Fixed, and pinned by a test that reads both sides.CUSTOM_AI_NOTICE.mdstill said the setting lives on the General tab — it moved to Notices & Agreements. Corrected.Validation
functional_tests/test_v2_chat_notices.py— 8/8 (new)test_ai_notice,test_user_settings_allowlist_keys,test_v2_api_payload_shapes,test_v2_settings_and_workspace_tags,test_v2_settings_tabs,test_v2_api_security,test_v2_ui_local_assets,test_v2_conversation_details_and_gating,test_v2_research_voice,test_docs_app_surface_coverage,test_docs_site_quality, and the admin-settings contract tests — all passnpm run build(tsc + vite) clean_build_noticesverified at runtime, confirming that editing the notice text invalidates existing dismissals and that all three web-search keys are requiredTwo pre-existing failures are unrelated and untouched:
test_chat_template_json_bootstrap_safety.py(a missingwindow.multiEndpointNoticeliteral inchats.html) and a Windows console-encoding quirk intest_user_settings_allowlist_keys.pythat passes underPYTHONIOENCODING=utf-8.Notes
docs/_data/app_surface.ymlis unchanged.lucide-reacticons and existinginfo/info-softtheme tokens, so CSP is untouched.dangerouslySetInnerHTML, matching V1's use oftextContent/Jinja escaping.0.261.027→0.261.028.Docs
docs/explanation/fixes/V2_CHAT_NOTICES_FIX.md(new)docs/explanation/features/REACT_V2_UI.md— new "Notices" section, bootstrap field, test table rowdocs/explanation/features/CUSTOM_AI_NOTICE.md— both interfaces, corrected tab namedocs/explanation/release_notes.md