diff --git a/src/renderer/src/components/settings/SessionHistoryComputerRow.test.tsx b/src/renderer/src/components/settings/SessionHistoryComputerRow.test.tsx index f23bf549584..8dbbe784786 100644 --- a/src/renderer/src/components/settings/SessionHistoryComputerRow.test.tsx +++ b/src/renderer/src/components/settings/SessionHistoryComputerRow.test.tsx @@ -80,7 +80,7 @@ function serverRow( ) } const serverSwitch = (): HTMLElement => - screen.getByRole('switch', { name: 'Index sessions on build-box' }) + screen.getByRole('switch', { name: 'Search sessions on build-box' }) beforeEach(() => { vi.useFakeTimers() @@ -107,16 +107,16 @@ it('renders a computer as icon, name, version, one status line and a switch', () kind="server" name="build-box" version="1.4.202" - status="Up to date · 12 files indexed" - details={['2 files could not be read and will be retried.']} + status="Ready · 12 sessions searchable" + details={['2 sessions could not be read and will be retried.']} checked onToggle={vi.fn()} /> ) expect(screen.getByText('build-box')).toBeInTheDocument() expect(screen.getByText('Orca v1.4.202')).toBeInTheDocument() - expect(screen.getByRole('status')).toHaveTextContent('Up to date · 12 files indexed') - expect(screen.getByText('2 files could not be read and will be retried.')).toBeInTheDocument() + expect(screen.getByRole('status')).toHaveTextContent('Ready · 12 sessions searchable') + expect(screen.getByText('2 sessions could not be read and will be retried.')).toBeInTheDocument() expect(serverSwitch()).toHaveAttribute('aria-checked', 'true') }) @@ -131,7 +131,7 @@ it('reports a reachable server by its live index status and version', async () = serverRow(connectedDetails()) await act(async () => {}) expect(mocks.status).toHaveBeenCalledWith('runtime:env-1') - expect(screen.getByRole('status')).toHaveTextContent('Up to date · 4880 files indexed') + expect(screen.getByRole('status')).toHaveTextContent('Ready · 4880 sessions searchable') expect(screen.getByText('Orca v1.4.202')).toBeInTheDocument() expect(serverSwitch()).toHaveAttribute('aria-checked', 'true') }) @@ -156,7 +156,7 @@ it('keeps an offline server dimmed, disabled and honest about its index', async await vi.advanceTimersByTimeAsync(30_000) }) expect(mocks.status).not.toHaveBeenCalled() - expect(screen.getByRole('status')).toHaveTextContent('Offline · index kept as it was') + expect(screen.getByRole('status')).toHaveTextContent('Offline') expect(serverSwitch()).toBeDisabled() expect(serverSwitch()).toHaveAttribute('aria-checked', 'false') }) @@ -171,13 +171,13 @@ it('asks for consent naming the server before enabling it', async () => { }) expect(confirm).toHaveBeenCalledWith( expect.objectContaining({ - title: 'Start indexing agent sessions on build-box?', - description: expect.stringContaining('This client only receives search results'), - confirmLabel: 'Start indexing' + title: 'Turn on session search on build-box?', + description: expect.stringContaining('results are sent to this computer'), + confirmLabel: 'Turn on' }) ) expect(mocks.setEnabled).toHaveBeenCalledWith('runtime:env-1', true) - expect(screen.getByRole('status')).toHaveTextContent('Up to date · 4880 files indexed') + expect(screen.getByRole('status')).toHaveTextContent('Ready · 4880 sessions searchable') }) it('leaves a server untouched when the consent is declined', async () => { @@ -214,9 +214,7 @@ it('turns a host-too-old rejection into the update-server state', async () => { await act(async () => { fireEvent.click(serverSwitch()) }) - expect(screen.getByRole('status')).toHaveTextContent( - 'Update this server to enable session search' - ) + expect(screen.getByRole('status')).toHaveTextContent('Needs a newer version of Orca.') expect(serverSwitch()).toBeDisabled() expect(onError).not.toHaveBeenCalledWith(expect.stringContaining('Could not change')) await act(async () => { diff --git a/src/renderer/src/components/settings/SessionHistoryComputerRow.tsx b/src/renderer/src/components/settings/SessionHistoryComputerRow.tsx index 1d0cf63ed8a..9d293b8b592 100644 --- a/src/renderer/src/components/settings/SessionHistoryComputerRow.tsx +++ b/src/renderer/src/components/settings/SessionHistoryComputerRow.tsx @@ -76,7 +76,7 @@ export function SessionHistoryComputerRow({ onChange={onToggle} ariaLabel={translate( 'sessionHistory.settings.rowSwitchLabel', - 'Index sessions on {{host}}', + 'Search sessions on {{host}}', { host: name } diff --git a/src/renderer/src/components/settings/SessionHistoryServerRow.tsx b/src/renderer/src/components/settings/SessionHistoryServerRow.tsx index acb99ed0eb3..bf2184363d4 100644 --- a/src/renderer/src/components/settings/SessionHistoryServerRow.tsx +++ b/src/renderer/src/components/settings/SessionHistoryServerRow.tsx @@ -84,15 +84,15 @@ export function SessionHistoryServerRow({ accepted = await confirm({ title: translate( 'sessionHistory.settings.serverEnableTitle', - 'Start indexing agent sessions on {{host}}?', + 'Turn on session search on {{host}}?', { host: environment.name } ), description: translate( 'sessionHistory.settings.serverEnableConsent', - 'Orca will build a search index on {{host}}. This client only receives search results. It copies conversation text and tool output from agent transcripts as written; content is not redacted. Indexing starts now, runs in the background, and the first scan can take several minutes. You can turn it off at any time; progress is kept.', + 'Orca will make the agent conversations and tool output on {{host}} searchable from Agent Session History. The searchable copy stays on {{host}}; results are sent to this computer when you search. The first pass runs in the background and can take a few minutes.', { host: environment.name } ), - confirmLabel: translate('sessionHistory.settings.enableConfirm', 'Start indexing') + confirmLabel: translate('sessionHistory.settings.enableConfirm', 'Turn on') }) } finally { if (mounted.current) { @@ -123,10 +123,7 @@ export function SessionHistoryServerRow({ dimmed checked={false} disabled - status={translate( - 'sessionHistory.settings.serverTooOld', - 'Update this server to enable session search.' - )} + status={translate('sessionHistory.settings.serverTooOld', 'Needs a newer version of Orca.')} action={{ label: translate('sessionHistory.settings.updateServer', 'Update server'), onClick: openServerSettings @@ -146,7 +143,7 @@ export function SessionHistoryServerRow({ status={ checking ? sessionSearchCheckingMessage() - : translate('sessionHistory.settings.serverOffline', 'Offline · index kept as it was') + : translate('sessionHistory.settings.serverOffline', 'Offline') } /> ) diff --git a/src/renderer/src/components/settings/SessionHistorySettingsPane.test.tsx b/src/renderer/src/components/settings/SessionHistorySettingsPane.test.tsx index dd41f809e25..c74246d42e3 100644 --- a/src/renderer/src/components/settings/SessionHistorySettingsPane.test.tsx +++ b/src/renderer/src/components/settings/SessionHistorySettingsPane.test.tsx @@ -106,7 +106,7 @@ it('requires opt-in and saves the existing policy without touching transcripts o const confirm = vi.fn().mockResolvedValue(true) pane(false, confirm, save) expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'false') - expect(screen.getByText(/Content is not redacted/)).toBeInTheDocument() + expect(screen.getByText(/Nothing leaves that computer/)).toBeInTheDocument() await act(async () => { await vi.advanceTimersByTimeAsync(60_000) }) @@ -116,9 +116,9 @@ it('requires opt-in and saves the existing policy without touching transcripts o }) expect(confirm).toHaveBeenCalledWith( expect.objectContaining({ - title: 'Start indexing agent sessions?', - description: expect.stringContaining('content is not redacted'), - confirmLabel: 'Start indexing' + title: 'Turn on session search?', + description: expect.stringContaining('It stays on this computer'), + confirmLabel: 'Turn on' }) ) expect(save).toHaveBeenCalledWith({ aiVaultSearch: { enabled: true, historyDays: null } }) @@ -167,10 +167,10 @@ it('shows failed saves inline and unlocks controls', async () => { it('hides the delete control behind Advanced', async () => { pane(false) - expect(screen.queryByRole('button', { name: 'Delete index' })).not.toBeInTheDocument() + expect(screen.queryByRole('button', { name: 'Clear' })).not.toBeInTheDocument() await openAdvanced() - expect(screen.getByRole('button', { name: 'Delete index' })).toBeInTheDocument() - expect(screen.getByText(/Search stays off/)).toBeInTheDocument() + expect(screen.getByRole('button', { name: 'Clear' })).toBeInTheDocument() + expect(screen.getByText(/Removes the searchable copy/)).toBeInTheDocument() }) it('deletes only after confirmation, supports deleting while disabled, and reports failures', async () => { @@ -178,20 +178,20 @@ it('deletes only after confirmation, supports deleting while disabled, and repor pane(false, confirm) await openAdvanced() await act(async () => { - fireEvent.click(screen.getByRole('button', { name: 'Delete index' })) + fireEvent.click(screen.getByRole('button', { name: 'Clear' })) }) expect(mocks.clear).not.toHaveBeenCalled() expect(confirm).toHaveBeenCalledWith( expect.objectContaining({ - title: 'Delete this computer’s search index?', - description: expect.stringContaining('Search stays off'), - confirmLabel: 'Delete index' + title: 'Clear search data on this computer?', + description: expect.stringContaining('Removes the searchable copy'), + confirmLabel: 'Clear' }) ) confirm.mockResolvedValue(true) mocks.clear.mockRejectedValue(new Error('service unavailable')) await act(async () => { - fireEvent.click(screen.getByRole('button', { name: 'Delete index' })) + fireEvent.click(screen.getByRole('button', { name: 'Clear' })) }) expect(mocks.clear).toHaveBeenCalledOnce() expect(screen.getByRole('alert')).toHaveTextContent('Could not clear') @@ -208,14 +208,12 @@ it('turns search off before deleting so the host does not rebuild the index', as pane(true, vi.fn().mockResolvedValue(true), save) await openAdvanced() await act(async () => { - fireEvent.click(screen.getByRole('button', { name: 'Delete index' })) + fireEvent.click(screen.getByRole('button', { name: 'Clear' })) }) expect(save).toHaveBeenCalledWith({ aiVaultSearch: { enabled: false, historyDays: null } }) expect(order).toEqual(['save', 'clear']) - expect(screen.getAllByText(/Switch search back on to rebuild/).length).toBeGreaterThan(0) - expect(toast.success).toHaveBeenCalledWith( - 'Search is off and the index was deleted. Original transcripts were kept.' - ) + expect(screen.getAllByText(/Turns off search and removes/).length).toBeGreaterThan(0) + expect(toast.success).toHaveBeenCalledWith('Search turned off and search data cleared.') }) it('deletes without a settings write when search is already off', async () => { @@ -223,13 +221,11 @@ it('deletes without a settings write when search is already off', async () => { pane(false, vi.fn().mockResolvedValue(true), save) await openAdvanced() await act(async () => { - fireEvent.click(screen.getByRole('button', { name: 'Delete index' })) + fireEvent.click(screen.getByRole('button', { name: 'Clear' })) }) expect(save).not.toHaveBeenCalled() expect(mocks.clear).toHaveBeenCalledOnce() - expect(toast.success).toHaveBeenCalledWith( - 'Search index cleared. Original transcripts were kept.' - ) + expect(toast.success).toHaveBeenCalledWith('Search data cleared.') }) it('keeps the index when turning search off fails', async () => { @@ -237,11 +233,11 @@ it('keeps the index when turning search off fails', async () => { pane(true, vi.fn().mockResolvedValue(true), save) await openAdvanced() await act(async () => { - fireEvent.click(screen.getByRole('button', { name: 'Delete index' })) + fireEvent.click(screen.getByRole('button', { name: 'Clear' })) }) expect(mocks.clear).not.toHaveBeenCalled() expect(screen.getByRole('alert')).toHaveTextContent('Could not save') - expect(screen.getByRole('button', { name: 'Delete index' })).toBeEnabled() + expect(screen.getByRole('button', { name: 'Clear' })).toBeEnabled() }) it('does not execute a confirmation after navigating away', async () => { @@ -251,7 +247,7 @@ it('does not execute a confirmation after navigating away', async () => { }) const view = pane(false, vi.fn().mockReturnValue(confirmation)) await openAdvanced() - fireEvent.click(screen.getByRole('button', { name: 'Delete index' })) + fireEvent.click(screen.getByRole('button', { name: 'Clear' })) view.unmount() await act(async () => { accept(true) @@ -264,7 +260,7 @@ it('leaves paired-client controls unsupported without local calls', async () => pane(true) expect(screen.getByRole('switch')).toBeDisabled() await openAdvanced() - expect(screen.getByRole('button', { name: 'Delete index' })).toBeDisabled() + expect(screen.getByRole('button', { name: 'Clear' })).toBeDisabled() await act(async () => { await vi.advanceTimersByTimeAsync(60_000) }) @@ -280,11 +276,11 @@ it('keeps the last index status visible while a save is in flight', async () => ) pane(true, vi.fn().mockResolvedValue(true), save) await act(async () => {}) - expect(screen.getByRole('status')).toHaveTextContent('Up to date · 12 files indexed') + expect(screen.getByRole('status')).toHaveTextContent('Ready · 12 sessions searchable') await act(async () => { fireEvent.click(screen.getByRole('switch')) }) - expect(screen.getByRole('status')).toHaveTextContent('Up to date · 12 files indexed') + expect(screen.getByRole('status')).toHaveTextContent('Ready · 12 sessions searchable') await act(async () => { finishSave() }) @@ -299,11 +295,11 @@ it('lists one row per paired Orca server under this computer, and says where SSH await act(async () => {}) const switches = screen.getAllByRole('switch') expect(switches).toHaveLength(3) - expect(screen.getByRole('switch', { name: 'Index sessions on build-box' })).toBeInTheDocument() - expect(screen.getByRole('switch', { name: 'Index sessions on office-mini' })).toBeInTheDocument() + expect(screen.getByRole('switch', { name: 'Search sessions on build-box' })).toBeInTheDocument() + expect(screen.getByRole('switch', { name: 'Search sessions on office-mini' })).toBeInTheDocument() expect(mocks.status).toHaveBeenCalledWith('local') expect( - screen.getByText('SSH hosts appear here once indexing is available on SSH.') + screen.getByText('Search from the Agent Session History panel in the sidebar.') ).toBeInTheDocument() }) diff --git a/src/renderer/src/components/settings/SessionHistorySettingsPane.tsx b/src/renderer/src/components/settings/SessionHistorySettingsPane.tsx index 969374c82cd..31fc5dba907 100644 --- a/src/renderer/src/components/settings/SessionHistorySettingsPane.tsx +++ b/src/renderer/src/components/settings/SessionHistorySettingsPane.tsx @@ -89,12 +89,12 @@ export function SessionHistorySettingsPane({ let accepted = false try { accepted = await confirm({ - title: translate('sessionHistory.settings.enableTitle', 'Start indexing agent sessions?'), + title: translate('sessionHistory.settings.enableTitle', 'Turn on session search?'), description: translate( 'sessionHistory.settings.enableConsent', - 'Orca will build a local search index on this computer. It copies conversation text and tool output from agent transcripts as written; content is not redacted. Indexing starts now, runs in the background, and the first scan can take several minutes. You can turn it off at any time; progress is kept.' + 'Orca will make your past agent conversations and tool output on this computer searchable from Agent Session History. It stays on this computer. The first pass runs in the background and can take a few minutes.' ), - confirmLabel: translate('sessionHistory.settings.enableConfirm', 'Start indexing') + confirmLabel: translate('sessionHistory.settings.enableConfirm', 'Turn on') }) } finally { if (mounted.current) { @@ -128,10 +128,10 @@ export function SessionHistorySettingsPane({ const accepted = await confirm({ title: translate( 'sessionHistory.settings.deleteTitle', - 'Delete this computer’s search index?' + 'Clear search data on this computer?' ), description: deleteDescription(wasEnabled), - confirmLabel: translate('sessionHistory.settings.delete', 'Delete index'), + confirmLabel: translate('sessionHistory.settings.delete', 'Clear'), confirmVariant: 'destructive' }) if (!accepted || !mounted.current) { @@ -148,18 +148,15 @@ export function SessionHistorySettingsPane({ wasEnabled ? translate( 'sessionHistory.settings.clearedAndTurnedOff', - 'Search is off and the index was deleted. Original transcripts were kept.' - ) - : translate( - 'sessionHistory.settings.cleared', - 'Search index cleared. Original transcripts were kept.' + 'Search turned off and search data cleared.' ) + : translate('sessionHistory.settings.cleared', 'Search data cleared.') ) } } catch { if (mounted.current) { setError( - translate('sessionHistory.settings.clearError', 'Could not clear the index. Try again.') + translate('sessionHistory.settings.clearError', 'Could not clear search data. Try again.') ) } } finally { @@ -185,17 +182,17 @@ export function SessionHistorySettingsPane({
{isWebClient ? translate( 'sessionHistory.settings.webUnsupported', - 'Manage indexing in the Orca desktop app on the computer that owns the transcripts. These controls are unavailable from a paired client.' + 'Turn on session search from the Orca desktop app on that computer.' ) : translate( 'sessionHistory.settings.computersConsent', - 'Each computer keeps a local index of its own transcripts, including conversation text and tool output as written. Content is not redacted. Turning a computer off stops indexing and keeps its index.' + 'Each computer keeps a searchable copy of its own agent conversations and tool output. Nothing leaves that computer.' )}
{translate( - 'sessionHistory.settings.sshNote', - 'SSH hosts appear here once indexing is available on SSH.' + 'sessionHistory.settings.panelHint', + 'Search from the Agent Session History panel in the sidebar.' )}
@@ -262,10 +259,7 @@ export function SessionHistorySettingsPane({ } function saveErrorMessage(): string { - return translate( - 'sessionHistory.settings.saveError', - 'Could not save session search settings. Try again.' - ) + return translate('sessionHistory.settings.saveError', 'Could not save. Try again.') } /** Shared by the Advanced row and its confirm dialog so both promise the same thing. */ @@ -273,10 +267,10 @@ function deleteDescription(enabled: boolean): string { return enabled ? translate( 'sessionHistory.settings.deleteEnabled', - 'Turn off search on this computer and remove its index. Original transcripts are not touched. Switch search back on to rebuild.' + 'Turns off search and removes the searchable copy from this computer. Your agent sessions are not affected.' ) : translate( 'sessionHistory.settings.deleteDisabled', - 'Remove the search index from this computer. Original transcripts are not touched. Search stays off.' + 'Removes the searchable copy from this computer. Your agent sessions are not affected.' ) } diff --git a/src/renderer/src/components/settings/session-history-status-copy.ts b/src/renderer/src/components/settings/session-history-status-copy.ts index 45de302ee62..8dd340745d3 100644 --- a/src/renderer/src/components/settings/session-history-status-copy.ts +++ b/src/renderer/src/components/settings/session-history-status-copy.ts @@ -21,15 +21,19 @@ export function sessionSearchPollIntervalMs(status: AiVaultSearchStatus | null): function sweepMessage(status: AiVaultSearchStatus): string { if (status.lastSweepCompletedAt === null) { // No completed sweep yet, so the denominator is still growing and a percentage would mislead. - return translate('sessionHistory.status.firstScan', 'Indexing… {{indexed}} files so far', { - indexed: status.filesIndexed - }) + return translate( + 'sessionHistory.status.firstScan', + 'Preparing search · {{indexed}} sessions so far', + { + indexed: status.filesIndexed + } + ) } const total = status.filesIndexed + status.filesDue + status.filesFailed const percent = total > 0 ? Math.floor((status.filesIndexed / total) * 100) : 0 return translate( 'sessionHistory.status.progress', - 'Indexing · {{percent}}% · {{indexed}} of {{total}} files', + 'Preparing search · {{percent}}% · {{indexed}} of {{total}} sessions', { percent, indexed: status.filesIndexed, total } ) } @@ -39,18 +43,18 @@ export function sessionSearchStatusMessage(status: AiVaultSearchStatus): string if (!status.enabled || status.phase === 'idle' || status.phase === 'closed') { return translate( 'sessionHistory.status.unavailable', - 'Index is not ready or the search service is unavailable.' + 'Search is not available on this computer right now.' ) } if (isSweepingSessionSearch(status)) { return sweepMessage(status) } - return translate('sessionHistory.status.upToDate', 'Up to date · {{indexed}} files indexed', { + return translate('sessionHistory.status.upToDate', 'Ready · {{indexed}} sessions searchable', { indexed: status.filesIndexed }) } -/** Lines shown under the status sentence while a host is actually indexing. */ +/** Lines shown under the status sentence when something needs the user's attention. */ export function sessionSearchStatusDetails(status: AiVaultSearchStatus | null): string[] { if (!status?.enabled) { return [] @@ -60,22 +64,14 @@ export function sessionSearchStatusDetails(status: AiVaultSearchStatus | null): lines.push( translate( 'sessionHistory.status.unreadable', - '{{failed}} files could not be read and will be retried.', + '{{failed}} sessions could not be read and will be retried.', { failed: status.filesFailed } ) ) } - if (isSweepingSessionSearch(status)) { - lines.push( - translate( - 'sessionHistory.status.stopHint', - 'Turn off search to stop. Progress is kept and resumes when you turn it back on.' - ) - ) - } if (status.degradedRoots.length > 0) { lines.push( - translate('sessionHistory.status.roots', 'Unverified source roots: {{roots}}', { + translate('sessionHistory.status.roots', '{{roots}} session folders could not be checked.', { roots: status.degradedRoots.length }) ) @@ -84,15 +80,15 @@ export function sessionSearchStatusDetails(status: AiVaultSearchStatus | null): } export function sessionSearchCheckingMessage(): string { - return translate('sessionHistory.status.checking', 'Checking index…') + return translate('sessionHistory.status.checking', 'Checking…') } export function sessionSearchOffMessage(): string { - return translate('sessionHistory.status.off', 'Search is off. Any existing index copy is kept.') + return translate('sessionHistory.status.off', 'Off') } export function sessionSearchReadErrorMessage(): string { - return translate('sessionHistory.status.error', 'Could not read index status. Retrying…') + return translate('sessionHistory.status.error', 'Could not check status. Retrying…') } // IPC wraps a rejection's message, so the host-too-old marker arrives inside a longer string. diff --git a/src/renderer/src/components/settings/settings-setup-workflow-section-renderers.tsx b/src/renderer/src/components/settings/settings-setup-workflow-section-renderers.tsx index 861df90842d..884534ae0bb 100644 --- a/src/renderer/src/components/settings/settings-setup-workflow-section-renderers.tsx +++ b/src/renderer/src/components/settings/settings-setup-workflow-section-renderers.tsx @@ -188,7 +188,7 @@ export function renderSessionHistorySettingsSection( title={translate('sessionHistory.settings.title', 'Agent Session History')} description={translate( 'sessionHistory.settings.description', - 'Each computer keeps its own index of the transcripts it owns. Turn on indexing here for this computer and for any paired Orca server.' + 'Search everything your agents have said and done, on this computer and on any paired Orca server.' )} searchEntries={navigation.getSectionSearchEntries('session-history')} > diff --git a/src/renderer/src/components/settings/use-session-search-status.test.tsx b/src/renderer/src/components/settings/use-session-search-status.test.tsx index b1d5558cc99..3b1558e7cc2 100644 --- a/src/renderer/src/components/settings/use-session-search-status.test.tsx +++ b/src/renderer/src/components/settings/use-session-search-status.test.tsx @@ -61,12 +61,12 @@ it('keeps polling a settled index so counts stay live between sweeps', async () const view = poll() await act(async () => {}) expect(mocks.status).toHaveBeenCalledWith('local') - expect(message(view.result.current.status)).toBe('Up to date · 12 files indexed') + expect(message(view.result.current.status)).toBe('Ready · 12 sessions searchable') mocks.status.mockResolvedValue({ ...current, filesIndexed: 30 }) await act(async () => { await vi.advanceTimersByTimeAsync(10_000) }) - expect(message(view.result.current.status)).toBe('Up to date · 30 files indexed') + expect(message(view.result.current.status)).toBe('Ready · 30 sessions searchable') }) it('reports a first scan by count and later sweeps by percentage', async () => { @@ -79,10 +79,8 @@ it('reports a first scan by count and later sweeps by percentage', async () => { }) const view = poll() await act(async () => {}) - expect(message(view.result.current.status)).toBe('Indexing… 4 files so far') - expect(sessionSearchStatusDetails(view.result.current.status)).toContain( - 'Turn off search to stop. Progress is kept and resumes when you turn it back on.' - ) + expect(message(view.result.current.status)).toBe('Preparing search · 4 sessions so far') + expect(sessionSearchStatusDetails(view.result.current.status)).toEqual([]) mocks.status.mockResolvedValue({ ...current, phase: 'indexing', @@ -94,7 +92,7 @@ it('reports a first scan by count and later sweeps by percentage', async () => { await act(async () => { await vi.advanceTimersByTimeAsync(2_000) }) - expect(message(view.result.current.status)).toBe('Indexing · 40% · 4 of 10 files') + expect(message(view.result.current.status)).toBe('Preparing search · 40% · 4 of 10 sessions') }) it('polls a sweep faster than a settled index', async () => { @@ -119,11 +117,10 @@ it('names unreadable files while degraded and still reports progress', async () }) const view = poll() await act(async () => {}) - expect(message(view.result.current.status)).toBe('Indexing · 80% · 8 of 10 files') + expect(message(view.result.current.status)).toBe('Preparing search · 80% · 8 of 10 sessions') expect(sessionSearchStatusDetails(view.result.current.status)).toEqual([ - '1 files could not be read and will be retried.', - 'Turn off search to stop. Progress is kept and resumes when you turn it back on.', - 'Unverified source roots: 1' + '1 sessions could not be read and will be retried.', + '1 session folders could not be checked.' ]) }) @@ -137,9 +134,9 @@ it('calls a drained degraded index up to date', async () => { }) const view = poll() await act(async () => {}) - expect(message(view.result.current.status)).toBe('Up to date · 9 files indexed') + expect(message(view.result.current.status)).toBe('Ready · 9 sessions searchable') expect(sessionSearchStatusDetails(view.result.current.status)).toEqual([ - '2 files could not be read and will be retried.' + '2 sessions could not be read and will be retried.' ]) }) @@ -148,7 +145,7 @@ it('does not describe an absent service as an empty current index', async () => const view = poll() await act(async () => {}) expect(message(view.result.current.status)).toBe( - 'Index is not ready or the search service is unavailable.' + 'Search is not available on this computer right now.' ) }) diff --git a/src/renderer/src/hooks/settings-navigation-workflow-sections.ts b/src/renderer/src/hooks/settings-navigation-workflow-sections.ts index 5e4414a2434..73c4210b32b 100644 --- a/src/renderer/src/hooks/settings-navigation-workflow-sections.ts +++ b/src/renderer/src/hooks/settings-navigation-workflow-sections.ts @@ -74,15 +74,15 @@ export function buildWorkflowSettingsSections( title: translate('sessionHistory.settings.title', 'Agent Session History'), description: translate( 'sessionHistory.settings.description', - 'Each computer keeps its own index of the transcripts it owns. Turn on indexing here for this computer and for any paired Orca server.' + 'Search everything your agents have said and done, on this computer and on any paired Orca server.' ), icon: History, searchEntries: [ { - title: translate('sessionHistory.settings.indexComputers', 'Index agent sessions'), + title: translate('sessionHistory.settings.indexComputers', 'Search agent sessions'), description: translate( 'sessionHistory.settings.searchDescription', - 'Transcript indexing on this computer and paired servers, index status and delete index.' + 'Turn on session search for this computer and paired servers, or clear search data.' ) } ], diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index c0a3c69b79a..25ad0067e1e 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -17942,47 +17942,46 @@ }, "sessionHistory": { "status": { - "checking": "Checking index…", - "off": "Search is off. Any existing index copy is kept.", - "error": "Could not read index status. Retrying…", - "unavailable": "Index is not ready or the search service is unavailable.", - "firstScan": "Indexing… {{indexed}} files so far", - "progress": "Indexing · {{percent}}% · {{indexed}} of {{total}} files", - "upToDate": "Up to date · {{indexed}} files indexed", - "unreadable": "{{failed}} files could not be read and will be retried.", - "stopHint": "Turn off search to stop. Progress is kept and resumes when you turn it back on.", - "roots": "Unverified source roots: {{roots}}" + "checking": "Checking…", + "off": "Off", + "error": "Could not check status. Retrying…", + "unavailable": "Search is not available on this computer right now.", + "firstScan": "Preparing search · {{indexed}} sessions so far", + "progress": "Preparing search · {{percent}}% · {{indexed}} of {{total}} sessions", + "upToDate": "Ready · {{indexed}} sessions searchable", + "unreadable": "{{failed}} sessions could not be read and will be retried.", + "roots": "{{roots}} session folders could not be checked." }, "settings": { - "saveError": "Could not save session search settings. Try again.", - "enableTitle": "Start indexing agent sessions?", - "enableConsent": "Orca will build a local search index on this computer. It copies conversation text and tool output from agent transcripts as written; content is not redacted. Indexing starts now, runs in the background, and the first scan can take several minutes. You can turn it off at any time; progress is kept.", - "enableConfirm": "Start indexing", + "saveError": "Could not save. Try again.", + "enableTitle": "Turn on session search?", + "enableConsent": "Orca will make your past agent conversations and tool output on this computer searchable from Agent Session History. It stays on this computer. The first pass runs in the background and can take a few minutes.", + "enableConfirm": "Turn on", "advanced": "Advanced", - "deleteIndexCopy": "Delete index copy", - "deleteTitle": "Delete this computer’s search index?", - "deleteEnabled": "Turn off search on this computer and remove its index. Original transcripts are not touched. Switch search back on to rebuild.", - "deleteDisabled": "Remove the search index from this computer. Original transcripts are not touched. Search stays off.", - "delete": "Delete index", - "cleared": "Search index cleared. Original transcripts were kept.", - "clearError": "Could not clear the index. Try again.", - "webUnsupported": "Manage indexing in the Orca desktop app on the computer that owns the transcripts. These controls are unavailable from a paired client.", + "deleteIndexCopy": "Clear search data", + "deleteTitle": "Clear search data on this computer?", + "deleteEnabled": "Turns off search and removes the searchable copy from this computer. Your agent sessions are not affected.", + "deleteDisabled": "Removes the searchable copy from this computer. Your agent sessions are not affected.", + "delete": "Clear", + "cleared": "Search data cleared.", + "clearError": "Could not clear search data. Try again.", + "webUnsupported": "Turn on session search from the Orca desktop app on that computer.", "title": "Agent Session History", - "description": "Each computer keeps its own index of the transcripts it owns. Turn on indexing here for this computer and for any paired Orca server.", - "searchDescription": "Transcript indexing on this computer and paired servers, index status and delete index.", - "indexComputers": "Index agent sessions", - "computersConsent": "Each computer keeps a local index of its own transcripts, including conversation text and tool output as written. Content is not redacted. Turning a computer off stops indexing and keeps its index.", - "sshNote": "SSH hosts appear here once indexing is available on SSH.", + "description": "Search everything your agents have said and done, on this computer and on any paired Orca server.", + "searchDescription": "Turn on session search for this computer and paired servers, or clear search data.", + "indexComputers": "Search agent sessions", + "computersConsent": "Each computer keeps a searchable copy of its own agent conversations and tool output. Nothing leaves that computer.", "serverVersion": "Orca v{{version}}", - "rowSwitchLabel": "Index sessions on {{host}}", - "serverOffline": "Offline · index kept as it was", - "serverTooOld": "Update this server to enable session search.", + "rowSwitchLabel": "Search sessions on {{host}}", + "serverOffline": "Offline", + "serverTooOld": "Needs a newer version of Orca.", "updateServer": "Update server", "serverOff": "Off", - "serverEnableTitle": "Start indexing agent sessions on {{host}}?", - "serverEnableConsent": "Orca will build a search index on {{host}}. This client only receives search results. It copies conversation text and tool output from agent transcripts as written; content is not redacted. Indexing starts now, runs in the background, and the first scan can take several minutes. You can turn it off at any time; progress is kept.", + "serverEnableTitle": "Turn on session search on {{host}}?", + "serverEnableConsent": "Orca will make the agent conversations and tool output on {{host}} searchable from Agent Session History. The searchable copy stays on {{host}}; results are sent to this computer when you search. The first pass runs in the background and can take a few minutes.", "serverToggleError": "Could not change session search on {{host}}. Try again.", - "clearedAndTurnedOff": "Search is off and the index was deleted. Original transcripts were kept." + "clearedAndTurnedOff": "Search turned off and search data cleared.", + "panelHint": "Search from the Agent Session History panel in the sidebar." } }, "aiVault": {