* Add pref and backend support for tab organization model key
Introduce kBraveAIChatTabOrganizationModelKey pref (default:
"chat-automatic") to allow users to choose which model is used
for tab organization. Update CreateTabOrganizationEngineIfNeeded
to read from this pref with fallback to "chat-automatic". Add
unit test for the invalid key fallback path.
* Add tab organization model selector in settings UI
Extract shared LeoModelSelector Lit component from personalization
page. Add tab organization model dropdown that appears when the tab
organization feature flag and pref are both enabled. Gate the tab
organization toggle behind the feature flag. Add localized string
for the model selector label.
* Improve tab focus prompts
When testing local model, found gemma tends to reply topics like
"['📰 News', '💻 Web Development', ... ]" which is failed to be parsed
because of the usage of single quotes on strings.
Improve tab focus prompts to mention valid JSON array and examples for
model to follow.
Fix Unlock and Cancel buttons not shown when creating new private tab with lock enabled
When "Require Touch ID/Face ID" was enabled for private tabs, the Unlock and Cancel buttons were hidden when creating a new private tab via the + button and cancelling the biometric prompt.
- Always show Unlock button when auth fails so user can retry
- Set isCancellable=true for non-external view types to show Cancel button
Signed-off-by: Eli Hini <8249954+EliHini@users.noreply.github.com>
* Show PageActionView for partitioned storage tab in location bar
When the current tab uses a Brave container (partitioned storage), show the
page action in the location bar with the container's icon, name, and
background color from ContainerModel.
- Register kPartitionedStorageActionIconType and enable it in the location
bar only when ENABLE_CONTAINERS and the Containers feature are on.
- Add PartitionedStoragePageActionController that resolves the tab's
container via GetContainerIdForWebContents and ContainerModel, and drives
the generic PageActionView (Show/Hide, OverrideImage/Text, etc.); the
action is hidden when the tab has no container.
The email aliases toggle in Brave Origin settings was always visible
regardless of whether the feature flag is enabled. Since the feature is
disabled by default, users would see a non-functional toggle.
Expose kEmailAliases to Java via ChromeFeatureList and hide the
preference when the flag is disabled.
Resolves: https://github.com/brave/brave-browser/issues/53323
* [iOS] Add package.json to control module type in iOS
This adds a new `package.json` in `//brave/ios` to ensure that usages of the iOS JS tooling `optimize_ts`/`compile_ts` use the correct module type (`nodenext`). This is a prerequisite to building Brave JavaScriptFeature's with TypeScript
* Migrate iOS webpack.config.js to ESM syntax
* Update to styles for upcoming wallet as sidepanel
effort to standadrize panels in desktop so the future wallet as a sidebar item can work correctly https://www.figma.com/design/Fbtxfv2ATGlfH7nPXiWAbR/%F0%9F%92%BB-Browser-Sidebar?node-id=1749-34459
* remove hardcoded background color that was messing up theming
* update backgrounds in panels so now they're themable
* update theme selector and toolbar customizer to be responsive.
Bonus, but it's very badly needed to have a properly responsive panel
* Address feedback
Address feedback from @fallaciousreasoning
* Delete unnecessary image files
* Formatting
---------
Co-authored-by: Simon Hong <shong@brave.com>
fix: DayZeroBrowserUIExptManager crashes when P3A is toggled off-on-off
ResetBrowserUIStateForAllProfiles() was resetting observation_ when P3A
was disabled, but SetDayZeroBrowserUIForAllProfiles() never re-established
it when P3A was re-enabled. Toggling P3A off a second time hit the
CHECK(observation_.IsObserving()) because the observation was already reset.
Remove the observation_.Reset() from ResetBrowserUIStateForAllProfiles().
It's unnecessary because OnProfileAdded() already guards on IsP3AEnabled(),
making it a no-op when P3A is off.
Also destroy the p3a_enabled_ pref subscription in
OnProfileManagerDestroying() to prevent the callback from firing after
the ProfileManager is gone.
Resolves: https://github.com/brave/brave-browser/issues/53294
* [AI Chat] [BYOM] Support tab focus in oai_engine and oai_api_client
- Use shared OAI message utils to build tab focus messages in oai_engine
- Translate customized tab focus content blocks to standard text content
blocks with prompts in oai_api_client
* [AI Chat] Handle empty tabs in tab focus APIs
Add early-return with InternalError when empty tabs are passed
to GetSuggestedTopics and GetFocusTabs, preventing
base::BarrierCallback from being created with 0 callbacks.
Follow-up fix for #34329 where a default WebKit configuration was being created anyways and would assert when `UseProfileWebViewConfiguration` was enabled.
* Add simplified candle.mojom interface
Add the CandleService and EmbeddingGemmaInterface mojom interfaces
for communication between the browser process and WASM renderer.
* Add CandleService and CandleServiceFactory
Add the CandleService KeyedService with background WebContents
management for running WASM in a hidden renderer. Includes the
CandleServiceFactory, idle timer for cleanup, and pending request
queue.
* Rename CandleService to LocalAIService
- Rename CandleService -> LocalAIService
- Rename CandleServiceFactory -> LocalAIServiceFactory
- Update all file names and references
- Add comprehensive class documentation explaining:
- Purpose: on-device ML capabilities
- Implementation: Currently uses Candle via WASM
- Architecture: Hidden WebContents + Mojo IPC
- Memory management: Idle timeout and cleanup
- Keep Candle-specific names for WASM bridge and resources
* Extract BackgroundWebContents interface for LocalAIService
Move background WebContents management from LocalAIService into a
BackgroundWebContents abstract interface (core/) with
BackgroundWebContentsImpl (content/) as the concrete implementation.
This follows the BackgroundContents delegate pattern from Chromium,
providing renderer crash detection and clean shutdown semantics.
LocalAIService now receives a factory callback instead of a
BrowserContext*, keeping it platform-agnostic and testable.
* Add unit tests for LocalAIService
Test request queueing, BindEmbeddingGemma processing pending
requests, Shutdown failing pending requests, and delegate
callback state reset on terminated/closed events.
* Add task manager integration for BackgroundWebContents
Tag the BackgroundWebContents with CreateForToolContents so it shows
up as "Tool: Local AI" in the task manager. Use a callback injected
by LocalAIServiceFactory to respect the components/chrome layering
boundary.
* Rename to model-agnostic terminology per review
- EmbeddingGemmaInterface -> OnDeviceModelWorker
- BindEmbeddingGemma -> RegisterOnDeviceModelWorker
- Embed -> GenerateEmbeddings
- kUntrustedCandleEmbeddingGemmaWasmURL -> kUntrustedOnDeviceModelWorkerURL
- URL: chrome-untrusted://on-device-model-worker/
- Internal members: embedding_gemma_remote_ -> model_worker_remote_,
PendingEmbedRequest -> PendingRequest, EnsureWasmWebContents ->
EnsureBackgroundContents, CloseWasmWebContents ->
CloseBackgroundContents
* Add PassageEmbedder interface and eliminate LocalAIService proxy
Introduce a shared PassageEmbedder mojom interface that replaces
OnDeviceModelWorker. Move the ReceiverSet and forwarding logic into
BackgroundWebContentsImpl so consumers get a Remote<PassageEmbedder>
bound directly to the content layer. LocalAIService becomes pure
lifecycle management with RegisterPassageEmbedder/GetPassageEmbedder.
* Replace PassageEmbedder proxy with PassageEmbedderFactory
BackgroundWebContentsImpl was acting as a ReceiverSet proxy between
consumers and the renderer's PassageEmbedder. Per review feedback,
this is an unnecessary layer — consumers should bind directly to the
renderer.
Introduce PassageEmbedderFactory (renderer-implemented) that creates
direct consumer→renderer PassageEmbedder bindings on demand. The
service manages the factory lifecycle and defers GetPassageEmbedder
callbacks until the factory is registered.
BackgroundWebContents interface is now pure lifecycle (no mojo).
BackgroundWebContentsImpl no longer implements mojom::PassageEmbedder.
* [AI Chat] Emit server search web source events from parser immediately
Move web source/query event extraction from
ConversationHandler::OnEngineCompletionComplete into the OAI
parser. ParseToolCallResult now returns all events (ToolUse +
WebSources + SearchQueries) and the API client fires them
individually through the streaming callback, so they arrive
immediately during streaming rather than being extracted
after completion.
* [AI Chat] Show web sources from earlier entries in task views
Source and search query events can arrive in earlier assistant
entries while the completion comes in a later entry in mixed
server and client tool case. Collect these events across all
entries and forward them to the completion step in both Progress
and Steps task views.
As upstream manages tab modal's reposition for split tabs, we don't need to have ours.
`ContentsContainerView`'s `TabModalDialogHost` does it.
Deleted code was added by https://github.com/brave/brave-core/pull/24540.
Other DEPS files are covered by netzenbot's automated checks
and gn check. Root DEPS is a code execution channel on checkout
and chromium_src DEPS can't be validated by gn check, so those
still need manual review.
Remove land-grab CODEOWNERS rules for Brave Account
The *brave_account* and *BraveAccount* wildcard rules match any file
path containing those strings, which is overly broad and triggers
unnecessary reviews. This is a "land-grab" pattern that taxes
productivity for developers who trigger those reviews.
Remove dead CODEOWNERS rules for deleted files
- script/build-bisect.py: file was removed
- browser/ui/webui/brave_web_uicontroller_factory.cc: file was removed
- browser/ui/webui/brave_rewards_page_ui.{cc,h}: files were removed
- browser/ui/webui/brave_rewards_ui.{cc,h}: files were removed
- third_party/boost: directory was removed
- brave/components/l10n/: wrong path prefix (brave/) so it never
matched anything, and the component is deprecated anyway
Chromium 146 introduced BadMessageException in the Java Mojo bindings
(crbug.com/469861566, https://github.com/chromium/chromium/commit/c04b8552deeef)
to surface malformed or unexpected messages (invalid headers, unknown methods,
deserialization errors, responses for already-cancelled requests). However, the
default ExceptionHandler simply re-throws the exception as unchecked, causing
crashes instead of gracefully closing the pipe.
This differs from the C++ Mojo bindings behavior where
Connector::DispatchMessage (mojo/public/cpp/bindings/lib/connector.cc) handles
dispatch failures by calling HandleError() which resets the pipe cleanly.
Set a delegate on ExceptionHandler.DefaultExceptionHandler that catches
BadMessageException and returns false (closing the pipe), while re-throwing
all other exceptions to preserve existing behavior.
Resolves: https://github.com/brave/brave-browser/issues/53290
Now that `TabStateFactory` is only used when creating actual tabs, the responsibility of passing in a nil `WKWebViewConfiguration` when `UseProfileWebViewConfiguration` is enabled can be shifted to the call site.
This also adds new asserts to ensure we aren't using TabManager's configurations when the feature flag is enabled.
This is a speculative fix for the URL bar being hidden after background Brave. It attempts to restore toolbar interactivity based on the keyboards state upon the scene activating along with adds additional checks during the visibility updates.
This is an upstream Chromium test
(chrome/browser/extensions/api/runtime/runtime_apitest.cc) that crashes
with a segmentation fault on Linux x64 nightly builds (issue #53280).
The test is already disabled on Mac upstream (IS_MAC). Upstream LUCI
Analysis shows occasional failures in the android_browsertests variant
(1.4% flake rate, increasing to 5-6% in late February/March 2026),
while the browser_tests desktop variant shows 0.3% flake rate.
No Brave chromium_src overrides exist for ProcessManager, service
worker lifecycle, or the chrome.runtime.getContexts() API, so this
failure is not caused by Brave-specific modifications.
Another test from the same fixture (GetOffscreenDocumentContext) is
already disabled in this filter file.
Disable flaky Chromium test AutoPictureInPictureTabHelperBrowserTest.PromptResultRecorded_VideoConferencingAllowOnce
This is an upstream Chromium test with a 10.5% flake rate over 30 days
per LUCI Analysis. The crash is a null pointer dereference in
AutoPipSettingView::OnButtonPressed when the widget is destroyed before
the test can interact with the bubble view.
Brave does not modify any code in the auto picture-in-picture path.
Multiple other tests from the same test suite are already disabled in
the filter file for similar reasons.
Resolves https://github.com/brave/brave-browser/issues/53277
Co-authored-by: Brian R. Bondy <netzen@gmail.com>
* Fix flaky BraveWalletSignMessageBrowserTest.SIWE test
The SIWE test sends two sign messages per iteration: one with matching
origin and one with a different origin ("www.a.com"). The second message
is rejected immediately by the provider, overwriting the global
signMessageResult variable with an error. After
NotifySignMessageRequestProcessed approves the first message, the test
immediately checked signMessageResult, but the mojo approval response
may not have been delivered to the renderer yet, so signMessageResult
still contained the rejection error.
Fix by replacing the immediate getSignMessageResult() check with a
Promise-based wait that polls until signMessageResult is a string
starting with "0x" (the signature). This is safe because both the
rejection and approval go through the same mojo interface, so the
rejection always arrives before the approval.
Resolves https://github.com/brave/brave-browser/issues/53167
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Address review: fix same race condition in other sign message tests
Apply the same async polling pattern to UserApprovedRequest and
UserRejectedRequest tests, which had the same race condition of
calling getSignMessageResult() immediately after
NotifySignMessageRequestProcessed() without waiting for the mojo
response to arrive at the renderer.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove secret key material from log messages
CRITICAL: Several VLOG(1) statements were logging plaintext secret
key material that could be captured via adb logcat (Android) or
Console.app (iOS):
- browser/android/brave_sync_worker.cc: Sync recovery phrase (seed
words) and hex-encoded sync seed logged on parse failure
- ios/browser/api/sync/brave_sync_worker.cc: Same issue on iOS
- components/brave_wallet/browser/filecoin_keyring.cc: Import payload
containing Filecoin private key logged on JSON parse failure
These log statements would expose the user's master sync secret or
private key material to any process with log access. The fix removes
the secret material from all log messages while preserving the
diagnostic error information.
* fix: also redact plaintext sync code from LOG(ERROR) in SetSyncCode (iOS) and SaveCodeWords (Android)
* fix: apply clang-format to sync worker files