perf: optimize app startup and background lifecycles

This commit is contained in:
inman
2026-08-19 00:56:15 +08:00
parent 31332f6d76
commit 927e13349b
121 changed files with 4359 additions and 1400 deletions

View File

@@ -16,6 +16,7 @@ import {
updateImageWorkspaceGenerationQuote,
} from '@/lib/image-workspace';
import { useAuthStore } from '@/stores/auth';
import { setDesktopBackgroundLease } from '@/lib/host-api';
import {
IMAGE_WORKSPACE_UNAVAILABLE_CODE,
type DesignAssistantDeltaEvent,
@@ -109,6 +110,18 @@ let projectDeletionGeneration = 0;
let generationQuoteUpdateSequence = 0;
let reconcileTaskStateOnNextConnect = false;
function updateBackgroundLease(input: {
id: string;
kind: string;
active: boolean;
}): void {
try {
void Promise.resolve(setDesktopBackgroundLease(input)).catch(() => undefined);
} catch {
// Renderer-only tests and embedded previews may not expose lifecycle IPC.
}
}
function taskRevisionKey(workspaceId: string, taskId: string): string {
return `${workspaceId}:${taskId}`;
}
@@ -376,7 +389,70 @@ function replaceGenerationQuote(
}
export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) => {
const pendingAssistantDeltas: DesignAssistantDeltaEvent[] = [];
let assistantDeltaFlushTimer: ReturnType<typeof setTimeout> | null = null;
const applyAssistantDelta = (
state: ImageWorkspaceState,
delta: DesignAssistantDeltaEvent,
): ImageWorkspaceState => {
if (state.activeWorkspaceId !== delta.workspaceId
|| state.activeConversationId !== delta.conversationId
|| (state.conversation?.turnRevision ?? 0) >= delta.turnRevision) {
return state;
}
const pending = state.pendingTurn;
if (!pending) {
if (delta.chunkIndex !== 0) return state;
return {
...state,
pendingTurn: {
workspaceId: delta.workspaceId,
conversationId: delta.conversationId,
clientTurnId: delta.clientTurnId,
turnRevision: delta.turnRevision,
userText: null,
assistantText: delta.delta,
lastChunkIndex: delta.chunkIndex,
createdAt: new Date().toISOString(),
},
};
}
if (pending.workspaceId !== delta.workspaceId
|| pending.conversationId !== delta.conversationId
|| pending.clientTurnId !== delta.clientTurnId
|| pending.turnRevision !== delta.turnRevision
|| delta.chunkIndex !== pending.lastChunkIndex + 1) {
return state;
}
return {
...state,
pendingTurn: {
...pending,
assistantText: `${pending.assistantText}${delta.delta}`,
lastChunkIndex: delta.chunkIndex,
},
};
};
const flushAssistantDeltas = () => {
assistantDeltaFlushTimer = null;
if (pendingAssistantDeltas.length === 0) return;
const queued = pendingAssistantDeltas.splice(0, pendingAssistantDeltas.length);
set((state) => queued.reduce(applyAssistantDelta, state));
};
const queueAssistantDelta = (delta: DesignAssistantDeltaEvent) => {
pendingAssistantDeltas.push(delta);
if (assistantDeltaFlushTimer === null) {
assistantDeltaFlushTimer = setTimeout(flushAssistantDeltas, 50);
}
};
const stopTaskStream = () => {
pendingAssistantDeltas.length = 0;
if (assistantDeltaFlushTimer !== null) clearTimeout(assistantDeltaFlushTimer);
assistantDeltaFlushTimer = null;
closeTaskEventSource();
set({ taskStreamState: 'idle' });
};
@@ -414,43 +490,7 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
if (!delta
|| delta.workspaceId !== activeTaskEventWorkspaceId
|| delta.conversationId !== activeTaskEventConversationId) return;
set((state) => {
if (state.activeWorkspaceId !== delta.workspaceId
|| state.activeConversationId !== delta.conversationId
|| (state.conversation?.turnRevision ?? 0) >= delta.turnRevision) {
return state;
}
const pending = state.pendingTurn;
if (!pending) {
if (delta.chunkIndex !== 0) return state;
return {
pendingTurn: {
workspaceId: delta.workspaceId,
conversationId: delta.conversationId,
clientTurnId: delta.clientTurnId,
turnRevision: delta.turnRevision,
userText: null,
assistantText: delta.delta,
lastChunkIndex: delta.chunkIndex,
createdAt: new Date().toISOString(),
},
};
}
if (pending.workspaceId !== delta.workspaceId
|| pending.conversationId !== delta.conversationId
|| pending.clientTurnId !== delta.clientTurnId
|| pending.turnRevision !== delta.turnRevision
|| delta.chunkIndex !== pending.lastChunkIndex + 1) {
return state;
}
return {
pendingTurn: {
...pending,
assistantText: `${pending.assistantText}${delta.delta}`,
lastChunkIndex: delta.chunkIndex,
},
};
});
queueAssistantDelta(delta);
});
source.addEventListener('design.conversation.snapshot', (event) => {
const snapshot = parseConversationSnapshotEvent(event);
@@ -579,7 +619,7 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
const message = messageOf(error);
if (authenticationRequired(error)) {
projectDeletionGeneration += 1;
closeTaskEventSource();
stopTaskStream();
useAuthStore.getState().invalidateSession();
set({
status: 'auth-required',
@@ -735,7 +775,7 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
)
? currentId
: bootstrap.workspaces[0]?.workspaceId ?? null;
closeTaskEventSource();
stopTaskStream();
set({
status: 'ready',
bootstrap,
@@ -753,7 +793,7 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
} catch (error) {
const message = handleRequestError(error);
if (!authenticationRequired(error)) {
closeTaskEventSource();
stopTaskStream();
set({
status: unavailable(error) ? 'unavailable' : 'error',
bootstrap: null,
@@ -877,7 +917,7 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
workspaceLoadGeneration += 1;
conversationSelectionGeneration += 1;
reconcileTaskStateOnNextConnect = false;
closeTaskEventSource();
stopTaskStream();
const nextWorkspaceId = mostRecentlyUpdatedWorkspace(remainingWorkspaces)?.workspaceId
?? null;
set({
@@ -1027,7 +1067,7 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
const shouldReconcile = reconcileTaskStateOnNextConnect;
reconcileTaskStateOnNextConnect = false;
if (shouldReconcile && get().taskStreamState !== 'connected') {
closeTaskEventSource();
stopTaskStream();
}
if (workspaceId && conversationId) startTaskStream(workspaceId, conversationId);
if (!workspaceId || !conversationId || !shouldReconcile) return;
@@ -1049,6 +1089,8 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
const userText = message.trim();
const clientTurnId = createImageWorkspaceTurnId();
if (!workspace || !conversation) throw new Error('请先选择设计会话');
const leaseId = `canvas:${workspace.workspaceId}:${clientTurnId}`;
updateBackgroundLease({ id: leaseId, kind: 'canvas-generation', active: true });
try {
set({
pendingTurn: createPendingTurn(conversation, clientTurnId, userText),
@@ -1087,6 +1129,8 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
: state.pendingTurn,
}));
return await recoverRevisionConflict(error);
} finally {
updateBackgroundLease({ id: leaseId, kind: 'canvas-generation', active: false });
}
},
@@ -1147,6 +1191,8 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
const conversation = get().conversation;
if (!workspace || !conversation) throw new Error('请先选择设计会话');
const clientTurnId = createImageWorkspaceTurnId();
const leaseId = `canvas:${workspace.workspaceId}:${clientTurnId}`;
updateBackgroundLease({ id: leaseId, kind: 'canvas-generation', active: true });
const requestWorkspaceLoadGeneration = workspaceLoadGeneration;
const requestConversationSelectionGeneration = conversationSelectionGeneration;
const isActiveConfirmationWorkspace = (): boolean => (
@@ -1247,6 +1293,8 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
: state.pendingTurn,
}));
return await recoverRevisionConflict(error);
} finally {
updateBackgroundLease({ id: leaseId, kind: 'canvas-generation', active: false });
}
},
@@ -1257,7 +1305,7 @@ export const useImageWorkspaceStore = create<ImageWorkspaceState>((set, get) =>
projectDeletionGeneration += 1;
generationQuoteUpdateSequence += 1;
reconcileTaskStateOnNextConnect = false;
closeTaskEventSource();
stopTaskStream();
set({
status: 'idle',
bootstrap: null,