perf(activity): page, summarize and reconcile activity history in Main by index

Schema 57 rebuilds activity_history_records with order_seq (newer = larger;
a move to the front assigns a new maximum) and stored generated columns
(record_id, occurrence, status, status_group, kind, request_id,
conversation_id, project_id, created_at) with indexes. The order is migrated
from record_order_json exactly; legacy duplicates keep their occurrence and
only the first is shown. record_order_json is no longer written.

ActivityHistoryRepository owns the SQL: page({before, limit <= 500, filter,
projectId, conversationId}) newest first by index, summary() with the counts
and conversation titles/status the Activity page derived from the full list,
reconcile() joined with tasks with a renderer-localized detail line, update()
applied directly in SQL without reading the history, replace() for the
legacy migration, clear(). New activity-history:page/summary/reconcile IPC
with zod validation; page and summary run on the readonly worker.
perf:main measures 24,000 records: startup load 106 ms on Main (14 MB) ->
first page + summary 13.5 ms on the worker (0.6 ms loop block, 114 KB).
This commit is contained in:
mesalogo
2026-10-03 21:42:52 +08:00
parent 6aab78b9fa
commit 352da66dbd
14 changed files with 963 additions and 263 deletions
+12 -1
View File
@@ -67,7 +67,12 @@ import type {
AssistantExpert,
AssistantTask,
ExecutionStats,
ActivityHistoryPage,
ActivityHistoryPageRequest,
ActivityHistoryReconcileRequest,
ActivityHistorySnapshot,
ActivityHistorySummary,
ActivityHistorySummaryRequest,
ActivityHistoryUpdate,
ActivityRecord,
TokenUsageSummary,
@@ -1296,7 +1301,13 @@ const desktopApi: DesktopApi = {
},
clear: async () => {
await ipcRenderer.invoke(ipcChannels.activityHistoryClear)
}
},
page: (request: ActivityHistoryPageRequest) =>
ipcRenderer.invoke(ipcChannels.activityHistoryPage, request) as Promise<ActivityHistoryPage>,
summary: (request: ActivityHistorySummaryRequest) =>
ipcRenderer.invoke(ipcChannels.activityHistorySummary, request) as Promise<ActivityHistorySummary>,
reconcile: (request: ActivityHistoryReconcileRequest) =>
ipcRenderer.invoke(ipcChannels.activityHistoryReconcile, request) as Promise<number>
},
usage: {
getTokenSummary: () =>