From ffbe78f74a94d2032df5059251949e0f8cad108f Mon Sep 17 00:00:00 2001 From: Wxw-Gu Date: Mon, 14 Sep 2026 18:09:43 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/hooks/useSearchHistory.ts | 29 ++++++++++++++++++- .../ai-search-cache-consent.test.tsx | 10 +++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/search/hooks/useSearchHistory.ts b/src/renderer/src/components/search/hooks/useSearchHistory.ts index 3c2b4d3..f01c041 100644 --- a/src/renderer/src/components/search/hooks/useSearchHistory.ts +++ b/src/renderer/src/components/search/hooks/useSearchHistory.ts @@ -217,6 +217,33 @@ export function useSearchHistory({ onNotice('已恢复这条历史问题的最近结果') } + const readCachedResult = (cacheKey: string): AISearchCacheRecord | null => { + const exact = readSearchCache(cacheKey) + if (exact) return exact + try { + const requested = parseSearchCacheKey(cacheKey) + if (!requested) return null + const records = JSON.parse(localStorage.getItem(SEARCH_CACHE_KEY) || '[]') as AISearchCacheRecord[] + return records + .filter((record) => { + try { + const raw = JSON.parse(record.key) as unknown[] + const location = parseSearchCacheKey(record.key) + // Only legacy four-part keys may use compatibility lookup, and + // all base dimensions must still match the active request. + return raw.length === 4 && location?.scope === requested.scope && + location.contactMd5 === requested.contactMd5 && location.range === requested.range && + location.query === requested.query + } catch { + return false + } + }) + .sort((a, b) => b.createdAt - a.createdAt)[0] || null + } catch { + return null + } + } + const persistSearchResult = (input: PersistSearchResultInput): AISearchCacheRecord => { const record = createSearchCacheRecord({ ...input, @@ -288,7 +315,7 @@ export function useSearchHistory({ removeHistoryQuery, restoreHistoryQuery, applyCachedResult, - readCachedResult: readSearchCache, + readCachedResult, persistSearchResult, clearActiveResult, skipNextCache, diff --git a/tests/component/ai-search-cache-consent.test.tsx b/tests/component/ai-search-cache-consent.test.tsx index e5f83ae..052c5db 100644 --- a/tests/component/ai-search-cache-consent.test.tsx +++ b/tests/component/ai-search-cache-consent.test.tsx @@ -6,7 +6,7 @@ import { SEARCH_CACHE_KEY, buildSearchCacheKey } from '../../src/renderer/src/components/search/searchUtils' -import { makeSearchResult } from './support/ai-search-fixtures' +import { makePipelineEvidence, makeSearchResult } from './support/ai-search-fixtures' const api = { getSettings: vi.fn(), @@ -224,7 +224,7 @@ describe('AISearchWorkspace cache privacy boundary', () => { value: scrollIntoView }) api.getAiSearchProviderStatus.mockResolvedValue({ configured: true, requiresConsent: false }) - api.runAiSearch.mockResolvedValue({ + api.runAiSearch.mockResolvedValue(makeSearchResult({ requestId: 'evidence-navigation', status: 'completed', answer: '请查看这条证据 [E7]。', @@ -264,7 +264,7 @@ describe('AISearchWorkspace cache privacy boundary', () => { agent: { mode: 'agent', toolCalls: 1, trace: [] }, timings: {}, elapsedMs: 1 - } as never) + }) as never) render( { it('keeps the submitted result title stable while drafting a new question and clears it from 新问题', async () => { api.getAiSearchProviderStatus.mockResolvedValue({ configured: true, requiresConsent: false }) - api.runAiSearch.mockResolvedValue({ + api.runAiSearch.mockResolvedValue(makeSearchResult({ requestId: 'new-question', status: 'completed', answer: 'first answer', @@ -319,7 +319,7 @@ describe('AISearchWorkspace cache privacy boundary', () => { agent: { mode: 'agent', toolCalls: 1, trace: [] }, timings: {}, elapsedMs: 1 - } as never) + }) as never) render(