Skip to content

Add Customize Responses to NTP omnibar Tools menu - #2865

Merged
moon0326 merged 20 commits into
mainfrom
feature/anpete/ntp-customize-responses
Jul 16, 2026
Merged

Add Customize Responses to NTP omnibar Tools menu#2865
moon0326 merged 20 commits into
mainfrom
feature/anpete/ntp-customize-responses

Conversation

@anpete

@anpete anpete commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Asana Task/Github Issue: https://app.asana.com/1/137249556945/project/72649045549333/task/1215104074883750?focus=true

Description

Adds the Customize Responses entry to the NTP AI chat Tools menu, wired through omnibar config and native messaging.

  • New config fields: enableCustomizeResponses, customizeSubLabel, hasCustomization, customizationActive
  • New notifies: omnibar_openCustomizeResponses, omnibar_setCustomizeResponsesActive
  • Tools menu row with glasses icon, optional sub-label, and on/off toggle when hasCustomization is true
  • Tools button collapses to icon-only when a tool is active or customizations are applied (customizationActive && hasCustomization)
  • Customize Responses is disabled while image generation is active
  • Separator above Customize Responses when the feature is enabled and tool rows are present

Testing Steps

  1. Checkout this branch and cd to special-pages
  2. Run npm run watch -- --page=new-tab
  3. Open http://127.0.0.1:8000/?omnibar.mode=ai&omnibar.enableCustomizeResponses=true&omnibar.hasCustomization=true&omnibar.customizationActive=true&omnibar.customizeSubLabel=Professional,%20Concise&omnibar.enableImageGeneration=true&omnibar.enableWebSearch=true
  4. Click the Tools menu icon
  5. Verify that Customize Response item renders.

Checklist

Please tick all that apply:

  • I have tested this change locally
  • I have tested this change locally in all supported browsers
  • This change will be visible to users
  • I have added automated tests that cover this change
  • I have ensured the change is gated by config
  • This change was covered by a ship review
  • This change was covered by a tech design
  • Any dependent config has been merged

Note

Medium Risk
New native messaging and config drive AI response customization UX; changes are config-gated but depend on correct native handling of open/toggle notifies.

Overview
Adds a Customize Responses row to the NTP AI chat Tools menu when enableCustomizeResponses is on, gated by omnibar config (customizeSubLabel, hasCustomization, customizationActive).

Menu construction moves into useToolsMenu / useCustomizeResponsesItem: the row opens the native modal via omnibar_openCustomizeResponses, and when the user has saved settings it shows an inline Switch that calls omnibar_setCustomizeResponsesActive. The Tools trigger collapses to icon-only when a tool chip is active or customization is applied; the row is disabled during image generation and separated from tool checkboxes when both are shown.

Shared Dropdown support grows for this pattern: separators, disabled rows, trailing controls (toggle clicks don’t fire the row), and keyboard navigation that skips non-actionable items.

Reviewed by Cursor Bugbot for commit 5b0be20. Bugbot is set up for automated code reviews on this repo. Configure here.

anpete added 8 commits July 14, 2026 17:08
Bring the New Tab Page omnibar Tools-menu "Customize responses" row to
parity with the address bar: show the customization summary as the row
sub-heading and an on/off toggle once responses have been customized.

- omnibar-config: add hasCustomization + customizationActive
- new message omnibar_setCustomizeResponsesActive to apply/unapply the
  stored customization
- DropdownItem gains an interactive trailingControl slot; ToolsMenu
  renders the shared Switch bound to the active state
- service/provider wiring, strings, mock-transport support
Match the icon-only trigger state used when image or web search tools are selected.
Add disabled dropdown item support and remove dev-only mock query param overrides for customize config.
Use control-fill-primary when icon-only; hover and active states stay aligned with the expanded Tools button.
Only collapse when a stored customization exists and is active, not when customizationActive is stale after reset.
Replace the NTP customizer sliders glyph with the design-system Glasses-16 icon.
Only show the divider when customize responses is enabled and tool rows are present above it.
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

[Beta] Generated file diff

Time updated: Thu, 16 Jul 2026 17:38:03 GMT

Apple
    - apple/pages/new-tab/dist/index.css
  • apple/pages/new-tab/dist/index.js
  • apple/pages/new-tab/locales/en/new-tab.json

File has changed

Integration
    - integration/pages/new-tab/dist/index.css
  • integration/pages/new-tab/dist/index.js
  • integration/pages/new-tab/locales/en/new-tab.json

File has changed

Windows
    - windows/pages/new-tab/dist/index.css
  • windows/pages/new-tab/dist/index.js
  • windows/pages/new-tab/locales/en/new-tab.json

File has changed

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Cursor review was not successful.

This PR requires a manual review and approval from a member of one of the following teams:

  • @duckduckgo/content-scope-scripts-owners
  • @duckduckgo/apple-devs
  • @duckduckgo/android-devs
  • @duckduckgo/team-windows-development
  • @duckduckgo/extension-owners
  • @duckduckgo/config-aor
  • @duckduckgo/breakage-aor
  • @duckduckgo/breakage

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Build Branch

Branch pr-releases/feature/anpete/ntp-customize-responses
Commit ff92067bf6
Updated July 16, 2026 at 5:37:20 PM UTC

Static preview entry points

QR codes (mobile preview)
Entry point QR code
Docs QR for docs preview
Static pages QR for static pages preview
Integration pages QR for integration pages preview

Integration commands

npm (Android / Extension):

npm i github:duckduckgo/content-scope-scripts#pr-releases/feature/anpete/ntp-customize-responses

Swift Package Manager (Apple):

.package(url: "https://github.com/duckduckgo/content-scope-scripts.git", branch: "pr-releases/feature/anpete/ntp-customize-responses")

git submodule (Windows):

git -C submodules/content-scope-scripts fetch origin pr-releases/feature/anpete/ntp-customize-responses
git -C submodules/content-scope-scripts checkout origin/pr-releases/feature/anpete/ntp-customize-responses
Pin to exact commit

npm (Android / Extension):

npm i github:duckduckgo/content-scope-scripts#ff92067bf643ad3d189a0cbab69f77e280aa56cc

Swift Package Manager (Apple):

.package(url: "https://github.com/duckduckgo/content-scope-scripts.git", revision: "ff92067bf643ad3d189a0cbab69f77e280aa56cc")

git submodule (Windows):

git -C submodules/content-scope-scripts fetch origin pr-releases/feature/anpete/ntp-customize-responses
git -C submodules/content-scope-scripts checkout ff92067bf643ad3d189a0cbab69f77e280aa56cc

@github-actions github-actions Bot added the semver-minor New feature — triggers minor version bump label Jul 14, 2026
Align generated types with the updated type generator output on CI.

@moon0326 moon0326 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @anpete for working on this 🙏

Overall it works as expected. One thing I'd suggest changing is how we render the "Customize responses" dropdown item.

Right now we pass a batch of props specific to customize responses to ToolsMenu (props): showCustomizeResponses, customizeResponsesSubLabel, hasCustomization, customizeResponsesActive, onSetCustomizeResponsesActive, and onOpenCustomizeResponses. These get threaded down through OmnibarConsumerOmnibarAiChatContentToolsMenu. That doesn't scale: every new menu entry of this kind adds another batch of props through the same three layers, and ToolsMenu's API keeps growing.

Worth noting we already avoid this for tools. useActiveTools reads its config straight from OmnibarContext, so ToolsMenu only takes tools, activeTool, and onToggle. Customize responses is the odd one out.

I'd refactor it so the config comes from OmnibarContext instead of props, the way useActiveTools already feeds the tools. Concretely: a useCustomizeResponses hook for the state and actions, and the row resolved to a uniform config rendered from the same .map the tools use. ToolsMenu then drops the six props and stays a 3-prop shell, so the next menu entry is another config source instead of more props and JSX.

I've prepared a commit that should give you some ideas: 0a0982b.

Happy to sync if needed.

@moon0326
moon0326 marked this pull request as ready for review July 14, 2026 18:51
Comment thread special-pages/pages/new-tab/types/new-tab.ts
The "Customize responses" row was passed into ToolsMenu as six
feature-specific props threaded through OmnibarConsumer, Omnibar, and
AiChatContent, which does not scale as more menu entries are added.

Read the customize config and actions from OmnibarContext via a
useCustomizeResponses hook, mirroring how useActiveTools feeds the
tools, and render every row (tools and customize) from one uniform
config list. Extract the customize row into useCustomizeResponsesItem
so the feature stays self-contained and ToolsMenu keeps a three-prop
surface (tools, activeTool, onToggle).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Web Compatibility Assessment

File Lines Severity Finding
special-pages/pages/new-tab/app/omnibar/components/chat-tools/dropdown/Dropdown.js 65–66, 132–139 warning DropdownSeparator children return {} from getItemProps() (not null), so separators are included in navigableIndices. Arrow/Home/End can land on a separator; aria-activedescendant may reference an id injected via cloneElement that DropdownSeparator does not forward to its <li>, producing a phantom focus target. Filter separators out of getNavigableIndices() (e.g. treat role="separator" or return null from getItemProps for non-item children).
special-pages/pages/new-tab/app/omnibar/components/chat-tools/tools-menu/useCustomizeResponsesItem.js 51–64 warning Keyboard Space/Enter on the customize-responses row invokes onSelect (opens modal) via Dropdown.handleKeyDown; the embedded Switch only receives mouse clicks (stopPropagation on the trailing span). Keyboard users cannot toggle the switch without Tab-stopping into it. Consider role="menuitemcheckbox" with row-level toggle behavior, or intercept Space when focus is on a row with trailingControl.
special-pages/pages/new-tab/app/omnibar/components/chat-tools/dropdown/Dropdown.js 65–66 info Disabled rows (e.g. customize-responses when image-generation is active) remain in navigableIndices; keyboard can highlight them but selectAt no-ops. Acceptable given aria-disabled + pointer-events: none, but skipping disabled indices would be cleaner.
All special-pages/ changes info No injected/ changes. This code runs in the embedded first-party NTP, not in third-party page context — no browser API fidelity, prototype-chain, or third-party script detection concerns apply.

Security Assessment

File Lines Severity Finding
special-pages/pages/new-tab/app/omnibar/omnibar.service.js 214–224 info New notify() calls send fixed payloads ({} and { active }). No object spreading; no nativeData leakage risk.
special-pages/pages/new-tab/app/omnibar/components/chat-tools/useCustomizeResponses.js 14 info Feature visibility gated with strict config?.enableCustomizeResponses === true (default false in schema). Native can remotely disable per window.
special-pages/pages/new-tab/messages/omnibar_openCustomizeResponses.notify.json 1–7 info Schema lacks additionalProperties: false (consistent with most omnibar notifies like omnibar_viewAllAIChats; only omnibar_submitChat enforces it). Low risk given empty fixed payload.
special-pages/pages/new-tab/messages/omnibar_setCustomizeResponsesActive.notify.json 1–15 info Same additionalProperties note; active is a required boolean — no injection surface.
special-pages/pages/new-tab/app/omnibar/components/chat-tools/tools-menu/useCustomizeResponsesItem.js 49 info customizeSubLabel from native config is rendered as Preact text content (auto-escaped). No dangerouslySetInnerHTML.

Risk Level

Low Risk — special-pages NTP omnibar UI only; no injected runtime, API overrides, messaging transport changes, or security-boundary modifications.

Recommendations

  1. (warning) Exclude DropdownSeparator from getNavigableIndices() and ensure separator <li> elements are not aria-activedescendant targets.
  2. (warning) Align keyboard behavior for the customize-responses toggle with mouse behavior (row Space/Enter toggles when hasCustomization, or document Tab-to-switch as intentional).
  3. (info) Add integration tests for the customize-responses row (visibility gating, toggle notify, disabled-when-image-gen, separator placement) — mock transport already handles both notifies.
  4. (info) Consider additionalProperties: false on new notify schemas for consistency with stricter messages.

Synchronize note (cab5a3b)

Latest commit refactors customize-responses into useCustomizeResponses / useCustomizeResponsesItem hooks (mirrors useActiveTools pattern), removing prop drilling through OmnibarToolsMenu. Separator now renders only when index > 0. No new compatibility or security surface introduced by the refactor.

Open in Web View Automation 

Sent by Cursor Automation: Web compat and sec

Wire up omnibar.enableCustomizeResponses, omnibar.customizeSubLabel,
omnibar.hasCustomization, and omnibar.customizationActive in the new-tab
mock transport, matching the existing omnibar.* overrides, so the
Customize responses row and its states can be exercised from the URL in
local dev.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread special-pages/pages/new-tab/app/omnibar/omnibar.service.js
- Skip separators and disabled rows in Dropdown keyboard navigation so
  arrow/Home/End never land on a non-actionable element or point
  aria-activedescendant at a separator.
- Drop native notify method names from omnibar config type descriptions.
- Add additionalProperties: false to the new customize-responses notify
  schemas, matching stricter omnibar messages.
daxtheduck
daxtheduck previously approved these changes Jul 15, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Injected PR Evaluation — Web Compatibility & Security

Re-assessed on synchronize (0fdc9c75f). Latest commit addresses prior review feedback (separator keyboard nav, additionalProperties: false on notify schemas).

Web Compatibility Assessment

File Lines Severity Finding
(none — injected/) No changes to injected runtime code. This PR is confined to special-pages/pages/new-tab/ (first-party NTP omnibar UI). Standard web-compat categories (API overrides, prototype patching, third-party script detection) do not apply.
Dropdown.js 71–77, 143–154 info getNavigableIndices() correctly skips DropdownSeparator and disabled rows — prior separator keyboard-nav concern is resolved in 0fdc9c75f.
Dropdown.js + useCustomizeResponsesItem.js 143–154 / 64 warning When the Customize Responses row is keyboard-focused, Space/Enter invoke onSelect (open modal) rather than toggling the embedded Switch. Mouse users can click the switch (stopPropagation on trailing control), but keyboard-only users cannot toggle without opening the modal first. Consider intercepting Space when focus is on the trailing control, or making the switch independently focusable within the menu.
useCustomizeResponsesItem.js 42, 50 info Row is disabled when activeTool === 'image-generation' — sensible mutual-exclusion with image-gen mode. pointer-events: none on disabled rows also blocks mouse access to the switch.
ToolsMenu.js 486–488 info Separator inserted only when customize-responses is not the first item — correct grouping UX.
(tests) info No dedicated integration tests for the customize-responses Tools menu row or toggle notify. Mock transport handles both new notifies; consider Playwright coverage for keyboard nav + toggle.

Security Assessment

File Lines Severity Finding
(none — injected/) No changes to captured-globals.js, message bridge, wrapper utilities, or injected features.
useCustomizeResponses.js 605 info Feature visibility gated on enableCustomizeResponses === true (schema default false) — supports remote rollback without deploy.
omnibar.service.js 666–675 info New notifies use explicit, minimal payloads: omnibar_openCustomizeResponses{}; omnibar_setCustomizeResponsesActive{ active: boolean }. No object spreading; no nativeData leakage risk.
omnibar_openCustomizeResponses.notify.json 6 info additionalProperties: falseadded in 0fdc9c75f, matching stricter omnibar message schemas.
omnibar_setCustomizeResponsesActive.notify.json 6, 10–12 info additionalProperties: false + required active: boolean — typed, closed schema.
useCustomizeResponsesItem.js 49 info customizeSubLabel from native config rendered as Preact text node — auto-escaped; no HTML injection vector.

Risk Level

Low Risk — Special-pages-only UI change with config-gated visibility, closed notify schemas, and no injected/API-override/messaging-transport modifications.

Recommendations

  1. (warning) Improve keyboard a11y for the embedded Switch: either focus-trap into the trailing control on ArrowRight, or suppress row-level Space/Enter when focus is within the switch.
  2. (info) Add integration tests covering: customize-responses row visibility (enableCustomizeResponses), toggle notify (omnibar_setCustomizeResponsesActive), separator keyboard nav, and disabled state during image-generation.
  3. (info) Confirm native platforms handle both new notifies before shipping (expected coordination).
Open in Web View Automation 

Sent by Cursor Automation: Web compat and sec

@moon0326
moon0326 requested a review from sashalavron July 15, 2026 20:38
Comment thread special-pages/pages/new-tab/app/omnibar/components/Omnibar.js Outdated
moon0326 added 3 commits July 16, 2026 08:36
Replace the numeric 1/-1 direction argument to focusNavigable with
'up'/'down' so call sites read clearly; the step is derived internally.
Move the menu-building logic out of ToolsMenu into a useToolsMenuItems
hook that composes all menu sources (tools + Customize responses) into a
single view model: { items, activeItem, isCollapsed }. ToolsMenu becomes
render-only, and Omnibar gates the menu on items.length instead of
checking availableTools and showCustomizeResponses separately, making the
data flow explicit and scalable as more menu entries are added.
Add a separatorBefore flag to the menu item config and set it on the
"Customize responses" row when tool rows precede it, so ToolsMenu renders
the divider from config instead of a customize-responses-specific
index check.
Comment thread special-pages/pages/new-tab/app/omnibar/omnibar.service.js
moon0326 added 2 commits July 16, 2026 10:33
Replace the nested ternary for the start position with an explicit
if/else, and use modulo for the wrap-around step.
@daxtheduck
daxtheduck dismissed their stale review July 16, 2026 17:35

Dismissing stale approval — new commits pushed, awaiting Cursor re-review.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ff7dbb2. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Injected PR Evaluation: Web Compatibility & Security

PR: Add Customize Responses to NTP omnibar Tools menu (ff7dbb2a)
Scope: special-pages/pages/new-tab/ only — no injected/, messaging/, or captured-globals changes. This UI runs in the first-party NTP embedded page, not in third-party page injection.


Web Compatibility Assessment

File Lines Severity Finding
(none in injected scope) info No browser API overrides, prototype patches, or DOM patterns that affect third-party sites.
dropdown/Dropdown.js 149–160 warning Keyboard vs trailing toggle: Space/Enter on the focused row invoke onSelect (opens Customize Responses modal) rather than toggling the embedded Switch. Mouse users can click the switch (stopPropagation on trailingControl), but keyboard-only users cannot operate the toggle from the menu.
dropdown/Dropdown.js 165–167 warning Tab closes menu: Tab schedules onClose({ restoreFocus: false }), so focus cannot move into the trailing Switch while the menu stays open.
dropdown/Dropdown.js 71–111 info Positive: getNavigableIndices() / focusNavigable('up'|'down') correctly skip DropdownSeparator rows and disabled items; aria-activedescendant won't point at separators.
tools-menu/useCustomizeResponsesItem.js 42, 49 info Customize Responses row is disabled when image-generation is active — avoids conflicting tool states.
tools-menu/useToolsMenu.js 74 info Tools button collapses to icon-only when a tool chip or active customization is shown — localized NTP layout change only.
omnibar/mocks/omnibar.mock-transport.js 203–208 warning Missing break: omnibar_setCustomizeResponsesActive falls through into omnibar_removeSuggestion, logging msg.params.url as undefined in local dev mocks.
integration-tests/ info No dedicated integration tests for the Customize Responses row or its notifies; existing tools-menu tests cover Create Image / Web Search only.

Security Assessment

File Lines Severity Finding
(scope) info Changes are confined to the NTP special page. Standard injected threat model (prototype tampering, captured-globals, message-bridge spoofing) does not apply.
omnibar.service.js 218–227 info Explicit notify payloads: notify('omnibar_openCustomizeResponses', {}) and notify('omnibar_setCustomizeResponsesActive', { active }) — no object spreading; no nativeData leakage risk.
messages/omnibar_*.notify.json info Both schemas set additionalProperties: false; toggle schema requires boolean active.
useCustomizeResponses.js 16 info Config-gated: showCustomizeResponses requires enableCustomizeResponses === true (schema default false) — remotely disableable without deploy.
useCustomizeResponsesItem.js 49 info customizeSubLabel from native config is rendered as Preact text (description prop) — auto-escaped; no dangerouslySetInnerHTML.
messages/types/omnibar-config.json 189–212 info New config fields are typed booleans/strings with defaults; no executable config surface.

Risk Level

Low Risk — Special-pages NTP UI only; no injected runtime, API shims, or messaging transport changes; feature is config-gated with tightly scoped notify schemas.


Recommendations

  1. (warning) Add break; after the omnibar_setCustomizeResponsesActive case in omnibar.mock-transport.js to prevent fall-through.
  2. (warning) Consider keyboard accessibility for the trailing Switch: e.g. don't preventDefault Space when focus is inside trailingControl, or expose a separate toggle action via keyboard.
  3. (info) Add integration tests asserting omnibar_openCustomizeResponses / omnibar_setCustomizeResponsesActive notifies when the row is selected and the toggle is clicked.
  4. (info) Coordinate native handler rollout for the two new notify methods before enabling enableCustomizeResponses in production config.
Open in Web View Automation 

Sent by Cursor Automation: Web compat and sec

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Injected PR Evaluation: Web Compatibility & Security

Re-assessed on synchronize (5b0be2087). Latest commit fixes the mock-transport break fallthrough flagged in the prior review.

Web Compatibility Assessment

File Lines Severity Finding
special-pages/pages/new-tab/app/omnibar/components/chat-tools/dropdown/Dropdown.js 149–160 warning Space/Enter on the highlighted row always invokes onSelect (opens Customize Responses modal). When trailingControl embeds a Switch, keyboard users cannot toggle active state from the row — only mouse clicks on the switch work (stopPropagation on click, not keydown). Consider forwarding Space/Enter to the focused trailing control or using a roving-tabindex pattern.
special-pages/pages/new-tab/app/omnibar/components/chat-tools/dropdown/Dropdown.js 165–167 warning Tab closes the menu (onClose({ restoreFocus: false })) before focus can move into the embedded Switch, so keyboard users cannot reach the toggle without the menu closing first.
special-pages/pages/new-tab/app/omnibar/components/chat-tools/tools-menu/useCustomizeResponsesItem.js 42, 50 info Row is disabled when image-generation is active (pointer-events: none via .itemDisabled). Consistent with product intent; disabled row is excluded from getNavigableIndices().
special-pages/pages/new-tab/app/omnibar/components/chat-tools/dropdown/Dropdown.js 71–79 info getNavigableIndices() / focusNavigable('up'/'down') correctly skip separators and disabled rows — avoids aria-activedescendant pointing at non-actionable elements.
(no injected/ changes) info No browser API overrides, prototype patches, or third-party page interaction. Web-compat evaluation categories (API fidelity, prototype chain, DOM on hostile pages) do not apply.

Security Assessment

File Lines Severity Finding
special-pages/pages/new-tab/app/omnibar/omnibar.service.js 218–227 info New notifies use explicit literal payloads ({}, { active }). No object spreading — nativeData leakage risk is low.
special-pages/pages/new-tab/messages/omnibar_openCustomizeResponses.notify.json 1–8 info Empty object schema with additionalProperties: false — page cannot inject extra fields.
special-pages/pages/new-tab/messages/omnibar_setCustomizeResponsesActive.notify.json 1–16 info Required boolean active with additionalProperties: false — well-bounded payload.
special-pages/pages/new-tab/app/omnibar/components/chat-tools/useCustomizeResponses.js 16 info Feature gated via config?.enableCustomizeResponses === true (schema default false). Native can disable per rollout without code deploy.
special-pages/pages/new-tab/app/omnibar/components/chat-tools/tools-menu/useCustomizeResponsesItem.js 49 info customizeSubLabel from native config is rendered as Preact text content ({description} in DropdownItem) — auto-escaped, no dangerouslySetInnerHTML. Trust boundary is native→NTP (first-party).
special-pages/pages/new-tab/app/omnibar/mocks/omnibar.mock-transport.js 203–207 info Fixed in 5b0be2087: omnibar_setCustomizeResponsesActive case now has break; — no longer falls through to omnibar_removeSuggestion.
(no injected/ changes) info No changes to captured-globals.js, message-bridge trust boundary, origin validation, or postMessage usage.

Risk Level

Low Risk — Changes are confined to the first-party NTP special-page (special-pages/pages/new-tab/); no injected content-script code, API shims, or messaging transport changes that affect third-party web pages.

Recommendations

  1. (warning) Improve keyboard a11y for the embedded Switch: either handle Space/Enter at the Dropdown level when trailingControl is present, or allow Tab to move focus into the switch without closing the menu.
  2. (info) Add an integration test for the customize-responses row (toggle visibility, disabled state during image generation, omnibar_openCustomizeResponses / omnibar_setCustomizeResponsesActive notifies) — mock transport and query-param overrides are already wired.
  3. (info) Coordinate native handling for the two new notifies and four config fields before enabling enableCustomizeResponses in production.

Positive notes

  • Config-gated with safe defaults (enableCustomizeResponses: false).
  • Message schemas use additionalProperties: false and explicit payloads.
  • Dropdown keyboard-nav refactor (getNavigableIndices, separator support, disabled rows) is a solid improvement shared by all Tools-menu rows.
  • Mock transport fallthrough from prior review is resolved.
Open in Web View Automation 

Sent by Cursor Automation: Web compat and sec

@moon0326
moon0326 added this pull request to the merge queue Jul 16, 2026
Merged via the queue into main with commit c5d74a0 Jul 16, 2026
40 of 41 checks passed
@moon0326
moon0326 deleted the feature/anpete/ntp-customize-responses branch July 16, 2026 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver-minor New feature — triggers minor version bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants