Files
brave-core/app
Anthony Tseng 371b87ab2b Add LocalAIService for on-device ML inference via Mojo (part 1) (#33724)
* 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.
2026-03-02 19:06:13 -08:00
..