From b89a6c634c7c16880767c35aaf1add3261deccff Mon Sep 17 00:00:00 2001 From: StroepWafel <109832156+StroepWafel@users.noreply.github.com> Date: Thu, 22 Jan 2026 11:37:09 +1030 Subject: [PATCH] fix vector initialisation? --- .npmrc | 2 + .../built-in/globalSearch/src/core/index.ts | 10 ++- .../src/indexing/worker/vectorWorker.ts | 62 ++++++++++++++++--- .../indexing/worker/vectorWorkerManager.ts | 31 ++++++++++ .../src/search/vector/vectorSearch.ts | 53 ++++++++++++++-- .../src/utils/browserDetection.ts | 30 +++++++++ 6 files changed, 174 insertions(+), 14 deletions(-) create mode 100644 .npmrc create mode 100644 src/plugins/built-in/globalSearch/src/utils/browserDetection.ts diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..8c1d73ae --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true + diff --git a/src/plugins/built-in/globalSearch/src/core/index.ts b/src/plugins/built-in/globalSearch/src/core/index.ts index cf6889ce..a5340f5a 100644 --- a/src/plugins/built-in/globalSearch/src/core/index.ts +++ b/src/plugins/built-in/globalSearch/src/core/index.ts @@ -126,10 +126,16 @@ const globalSearchPlugin: Plugin = { initVectorSearch(); - // Warm up vector worker in background to improve initial response time + // Warm up vector worker in background to improve initial response time (skip in Firefox) setTimeout(async () => { try { - VectorWorkerManager.getInstance(); + // Only initialize worker if vector search is supported + const { isVectorSearchSupported } = await import("../utils/browserDetection"); + if (isVectorSearchSupported()) { + VectorWorkerManager.getInstance(); + } else { + console.debug("[Global Search] Skipping vector worker warm-up (Firefox detected - using text search only)"); + } } catch (error) { console.warn("[Global Search] Vector worker warm-up failed:", error); } diff --git a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts index 4f4c3cb2..64f71f0d 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts @@ -3,9 +3,24 @@ import type { IndexItem } from "../types"; let vectorIndex: EmbeddingIndex | null = null; let isInitialized = false; +let initializationFailed = false; let currentAbortController: AbortController | null = null; let loadedItemIds = new Set(); +// Detect Firefox in worker context +function isFirefoxWorker(): boolean { + try { + // Check for Firefox-specific APIs or user agent + if (typeof navigator !== "undefined") { + return navigator.userAgent.toLowerCase().includes("firefox"); + } + // In worker context, check for Firefox-specific behavior + return false; + } catch { + return false; + } +} + let streamingSession: { isActive: boolean; totalExpected: number; @@ -21,6 +36,16 @@ async function initWorker() { console.debug("Vector worker already initialized."); return; } + + // Skip initialization in Firefox + if (isFirefoxWorker()) { + console.debug("[Vector Worker] Vector search not supported in Firefox - skipping initialization"); + isInitialized = true; + initializationFailed = true; + vectorIndex = null; + return; + } + console.debug("Initializing vector worker..."); try { await initializeModel(); @@ -48,8 +73,9 @@ async function initWorker() { isInitialized = true; console.debug("Vector worker initialized successfully."); } catch (e) { - console.error("Failed to initialize vector worker:", e); + console.warn("[Vector Worker] Failed to initialize vector worker (will use text search only):", e); isInitialized = true; + initializationFailed = true; vectorIndex = null; } } @@ -80,18 +106,29 @@ async function startStreamingSession( totalExpected: number, batchSize: number = 5, ) { + if (initializationFailed || isFirefoxWorker()) { + self.postMessage({ + type: "progress", + data: { + status: "complete", + message: "Vector search not available in Firefox - using text search only", + }, + }); + return; + } + if (!vectorIndex) { console.warn( "Streaming requested but vector index not ready. Attempting init.", ); await initWorker(); - if (!vectorIndex) { + if (!vectorIndex || initializationFailed) { self.postMessage({ type: "progress", data: { - status: "error", + status: "complete", message: - "Vector index not available for streaming after init attempt.", + "Vector index not available - using text search only", }, }); return; @@ -306,18 +343,29 @@ async function endStreamingSession() { async function processItems(items: IndexItem[], signal: AbortSignal) { console.debug("Worker received process request."); + if (initializationFailed || isFirefoxWorker()) { + self.postMessage({ + type: "progress", + data: { + status: "complete", + message: "Vector search not available - using text search only", + }, + }); + return; + } + if (!vectorIndex) { console.warn( "Processing requested but vector index not ready. Attempting init.", ); await initWorker(); - if (!vectorIndex) { + if (!vectorIndex || initializationFailed) { self.postMessage({ type: "progress", data: { - status: "error", + status: "complete", message: - "Vector index not available for processing after init attempt.", + "Vector index not available - using text search only", }, }); return; diff --git a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts index c9772efa..f9040996 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts @@ -1,5 +1,6 @@ import { refreshVectorCache } from "../../search/vector/vectorSearch"; import type { IndexItem } from "../types"; +import { isVectorSearchSupported } from "../../utils/browserDetection"; import vectorWorker from "./vectorWorker.ts?inlineWorker"; export type ProgressCallback = (data: { @@ -42,6 +43,13 @@ export class VectorWorkerManager { } private async initWorker(): Promise { + // Skip initialization if vector search is not supported (e.g., Firefox) + if (!isVectorSearchSupported()) { + console.debug("[VectorWorkerManager] Vector search not supported - skipping worker initialization"); + this.isInitialized = false; + return Promise.resolve(); + } + if (this.isInitialized) return Promise.resolve(); if (this.readyPromise) return this.readyPromise; @@ -234,6 +242,17 @@ export class VectorWorkerManager { } async processItems(items: IndexItem[], onProgress?: ProgressCallback) { + // Skip if vector search is not supported + if (!isVectorSearchSupported()) { + if (onProgress) { + onProgress({ + status: "complete", + message: "Vector search not available - using text search only" + }); + } + return; + } + // Only initialize worker if we actually have items to process if (items.length === 0) { if (onProgress) { @@ -298,6 +317,18 @@ export class VectorWorkerManager { batchSize: number = 10, jobId?: string, ): Promise { + // Skip if vector search is not supported + if (!isVectorSearchSupported()) { + console.debug("[VectorWorker] Vector search not supported - skipping streaming session"); + if (onProgress) { + onProgress({ + status: "complete", + message: "Vector search not available - using text search only", + }); + } + return; + } + // Only initialize if we expect items to process if (totalExpectedItems === 0) { console.debug("[VectorWorker] No items expected, not starting streaming session"); diff --git a/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts b/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts index 4bb68590..6f45fa6b 100644 --- a/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts +++ b/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts @@ -1,16 +1,36 @@ import { EmbeddingIndex, getEmbedding, initializeModel } from "embeddia"; import type { IndexItem } from "../../indexing/types"; import type { SearchResult } from "embeddia"; +import { isVectorSearchSupported } from "../../utils/browserDetection"; let vectorIndex: EmbeddingIndex | null = null; +let initializationAttempted = false; +let initializationFailed = false; export async function initVectorSearch() { + // Skip initialization if already attempted and failed, or if not supported + if (initializationFailed || !isVectorSearchSupported()) { + if (!isVectorSearchSupported()) { + console.debug("[Vector Search] Vector search not supported in Firefox - using text search only"); + } + return; + } + + if (initializationAttempted) { + return; + } + + initializationAttempted = true; + try { await initializeModel(); vectorIndex = new EmbeddingIndex([]); vectorIndex.preloadIndexedDB(); + console.debug("[Vector Search] Initialized successfully"); } catch (e) { - console.error("Error initializing vector search", e); + console.warn("[Vector Search] Failed to initialize vector search (will use text search only):", e); + initializationFailed = true; + vectorIndex = null; } } @@ -44,7 +64,17 @@ export async function searchVectors( query: string, topK: number = 20, ): Promise { - if (!vectorIndex) await initVectorSearch(); + // Return empty array if vector search is not supported or failed to initialize + if (!isVectorSearchSupported() || initializationFailed) { + return []; + } + + if (!vectorIndex) { + await initVectorSearch(); + if (!vectorIndex) { + return []; + } + } // Normalize query for caching const normalizedQuery = query.trim().toLowerCase().slice(0, 100); @@ -84,7 +114,20 @@ export async function searchVectors( } export async function refreshVectorCache() { - if (!vectorIndex) await initVectorSearch(); - vectorIndex!.clearIndexedDBCache(); - vectorIndex!.preloadIndexedDB(); + if (!isVectorSearchSupported() || initializationFailed) { + return; + } + + if (!vectorIndex) { + await initVectorSearch(); + } + + if (vectorIndex) { + try { + vectorIndex.clearIndexedDBCache(); + vectorIndex.preloadIndexedDB(); + } catch (e) { + console.warn("[Vector Search] Failed to refresh cache:", e); + } + } } diff --git a/src/plugins/built-in/globalSearch/src/utils/browserDetection.ts b/src/plugins/built-in/globalSearch/src/utils/browserDetection.ts new file mode 100644 index 00000000..7ad87c9f --- /dev/null +++ b/src/plugins/built-in/globalSearch/src/utils/browserDetection.ts @@ -0,0 +1,30 @@ +import browser from "webextension-polyfill"; + +/** + * Detects if the current browser is Firefox + */ +export function isFirefox(): boolean { + try { + // Firefox-specific API + if (typeof (browser.runtime as any).getBrowserInfo === "function") { + return true; + } + // Fallback: check user agent + if (typeof navigator !== "undefined") { + return navigator.userAgent.toLowerCase().includes("firefox"); + } + return false; + } catch { + // If we can't detect, assume not Firefox (safer for Chrome/Edge) + return false; + } +} + +/** + * Checks if vector search is supported in the current browser + * Currently disabled for Firefox due to security restrictions + */ +export function isVectorSearchSupported(): boolean { + return !isFirefox(); +} +