mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 08:01:56 +00:00
Cache browser history by identity and snapshot omnibox entries
- Use WeakMap to cache prepared browser history entries by identity, so re-parsing is skipped for the same snapshot - Change omnibox to read a history snapshot at menu open (via getState) instead of subscribing to live updates, preventing background navigations from reshuffling results mid-keystroke - Support fully-qualified URL prefix matching (e.g., `https://github.com`) to preserve address-bar behavior - Fix percentile calculation in performance tests (nearest-rank method)
This commit is contained in:
@@ -41,7 +41,7 @@ vi.mock('@/store', () => ({
|
||||
browserDefaultSearchEngine: 'google',
|
||||
getKnownWorktreeById: () => ({ path: '/tmp/wt' })
|
||||
}),
|
||||
{ getState: () => ({}) }
|
||||
{ getState: () => ({ browserUrlHistory: historyStoreMock.entries }) }
|
||||
)
|
||||
}))
|
||||
vi.mock('react', async () => {
|
||||
|
||||
@@ -85,9 +85,14 @@ export function useOmniboxBrowserHistory({
|
||||
query: string
|
||||
tabResults: readonly OpenTabSearchResult[]
|
||||
}): readonly BrowserHistoryOmniboxRow[] {
|
||||
// Why null while disabled: the tab bar is mounted for every workspace, and
|
||||
// this array is replaced on every committed navigation in any browser tab.
|
||||
const history = useAppStore((store) => (enabled ? store.browserUrlHistory : null))
|
||||
// Why read once: the tab bar is mounted for every workspace, and this array
|
||||
// is replaced on every committed navigation in any browser tab. History is
|
||||
// intentionally a per-open snapshot so background navigations cannot churn
|
||||
// the omnibox or reshuffle a selection under the user's fingers.
|
||||
const history = useMemo(
|
||||
() => (enabled ? useAppStore.getState().browserUrlHistory : null),
|
||||
[enabled]
|
||||
)
|
||||
const prepared = useMemo(
|
||||
() => (history ? prepareBrowserHistoryEntries(history) : null),
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps -- Snapshot per menu open; a background navigation must not reshuffle rows mid-keystroke.
|
||||
|
||||
@@ -26,7 +26,8 @@ const WORST_QUERY = 'observability rollout'
|
||||
|
||||
function percentile95(samples: number[]): number {
|
||||
const sorted = [...samples].sort((a, b) => a - b)
|
||||
return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95))]
|
||||
// Nearest-rank p95: ceil(n*0.95)-1, so 20 samples pick index 18 rather than the max.
|
||||
return sorted[Math.min(sorted.length - 1, Math.ceil(sorted.length * 0.95) - 1)]
|
||||
}
|
||||
|
||||
describe('browser history match performance budget', () => {
|
||||
@@ -41,7 +42,9 @@ describe('browser history match performance budget', () => {
|
||||
const samples: number[] = []
|
||||
for (let run = 0; run < 20; run += 1) {
|
||||
const start = performance.now()
|
||||
prepareBrowserHistoryEntries(entries)
|
||||
// Use a fresh array identity so this measures preparation rather than
|
||||
// the identity cache used by live address bars and omniboxes.
|
||||
prepareBrowserHistoryEntries(entries.slice())
|
||||
samples.push(performance.now() - start)
|
||||
}
|
||||
expect(percentile95(samples)).toBeLessThan(prepareP95Ms)
|
||||
|
||||
@@ -56,6 +56,12 @@ describe('browser history match', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('keeps fully-qualified URL prefixes in the top tier', () => {
|
||||
expect(match([entry({ url: 'https://github.com/acme' })], 'https://github.com')).toEqual([
|
||||
{ tier: 'host-prefix', url: 'https://github.com/acme' }
|
||||
])
|
||||
})
|
||||
|
||||
it('leaves a subdomain match in host-substring rather than host-prefix', () => {
|
||||
expect(match([entry({ url: 'https://docs.github.com/actions' })], 'git')).toEqual([
|
||||
{ tier: 'host-substring', url: 'https://docs.github.com/actions' }
|
||||
@@ -131,6 +137,13 @@ describe('browser history match', () => {
|
||||
expect(matchBrowserHistory({ prepared, query: 'git', limit: 0, now: NOW })).toBe(missA)
|
||||
})
|
||||
|
||||
it('reuses preparation for the same immutable history snapshot', () => {
|
||||
const first = prepareBrowserHistoryEntries(GIT_CORPUS)
|
||||
|
||||
expect(prepareBrowserHistoryEntries(GIT_CORPUS)).toBe(first)
|
||||
expect(prepareBrowserHistoryEntries([...GIT_CORPUS])).not.toBe(first)
|
||||
})
|
||||
|
||||
it('survives an unparseable url by falling back to url and title matching', () => {
|
||||
const broken = entry({ url: 'not a url at all', title: 'Broken' })
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@ export type BrowserHistoryMatch = {
|
||||
}
|
||||
|
||||
const NO_MATCHES: readonly BrowserHistoryMatch[] = []
|
||||
const preparedHistoryCache = new WeakMap<
|
||||
readonly BrowserHistoryEntry[],
|
||||
readonly PreparedBrowserHistoryEntry[]
|
||||
>()
|
||||
|
||||
function historyHost(url: string): string {
|
||||
try {
|
||||
@@ -53,13 +57,19 @@ export function formatBrowserHistoryUrl(url: string): string {
|
||||
export function prepareBrowserHistoryEntries(
|
||||
entries: readonly BrowserHistoryEntry[]
|
||||
): readonly PreparedBrowserHistoryEntry[] {
|
||||
return entries.map((entry) => ({
|
||||
const cached = preparedHistoryCache.get(entries)
|
||||
if (cached) {
|
||||
return cached
|
||||
}
|
||||
const prepared = entries.map((entry) => ({
|
||||
entry,
|
||||
lowerUrl: entry.url.toLowerCase(),
|
||||
lowerTitle: entry.title.toLowerCase(),
|
||||
lowerHost: historyHost(entry.url),
|
||||
frecencyBase: Math.min(entry.visitCount, MAX_VISIT_COUNT_BONUS)
|
||||
}))
|
||||
preparedHistoryCache.set(entries, prepared)
|
||||
return prepared
|
||||
}
|
||||
|
||||
function matchTier(
|
||||
@@ -69,7 +79,9 @@ function matchTier(
|
||||
// A workspace-doc entry's url is a filesystem path, so it has no host: a path
|
||||
// prefix is as deliberate as a host prefix and earns the same top tier.
|
||||
const prefixTarget = prepared.lowerHost === '' ? prepared.lowerUrl : prepared.lowerHost
|
||||
if (prefixTarget.startsWith(lowerQuery)) {
|
||||
// Preserve the address-bar's long-standing behavior for fully-qualified
|
||||
// input (e.g. `https://github.com`), while still ranking bare hosts by host.
|
||||
if (prefixTarget.startsWith(lowerQuery) || prepared.lowerUrl.startsWith(lowerQuery)) {
|
||||
return 'host-prefix'
|
||||
}
|
||||
if (prepared.lowerHost.includes(lowerQuery)) {
|
||||
|
||||
Reference in New Issue
Block a user