fix(chat): speed up history switch

This commit is contained in:
john
2026-06-29 11:15:40 +08:00
parent b7af5b00dc
commit 394d3640d1
2 changed files with 40 additions and 13 deletions
+27 -2
View File
@@ -67,10 +67,12 @@ export function HistorySidebar({
}: HistorySidebarProps) { }: HistorySidebarProps) {
const bodyRef = useRef<HTMLDivElement>(null); const bodyRef = useRef<HTMLDivElement>(null);
const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null); const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null);
const [pendingSelectId, setPendingSelectId] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
if (open) { if (open) {
setPendingDeleteId(null); setPendingDeleteId(null);
setPendingSelectId(null);
} }
}, [open, sessions.length]); }, [open, sessions.length]);
@@ -84,6 +86,7 @@ export function HistorySidebar({
}, [hasMore, loading, loadingMore, onLoadMore]); }, [hasMore, loading, loadingMore, onLoadMore]);
const handleDeleteClick = useCallback((sessionId: string) => { const handleDeleteClick = useCallback((sessionId: string) => {
setPendingSelectId(null);
setPendingDeleteId(sessionId); setPendingDeleteId(sessionId);
}, []); }, []);
@@ -99,6 +102,24 @@ export function HistorySidebar({
setPendingDeleteId(null); setPendingDeleteId(null);
}, []); }, []);
const handleSelectClick = useCallback(
(sessionId: string) => {
if (pendingDeleteId === sessionId) return;
if (activeSessionId === sessionId) {
setPendingSelectId(null);
onSelect(sessionId);
return;
}
if (pendingSelectId === sessionId) {
setPendingSelectId(null);
onSelect(sessionId);
return;
}
setPendingSelectId(sessionId);
},
[activeSessionId, onSelect, pendingDeleteId, pendingSelectId],
);
if (!open) return null; if (!open) return null;
const sessionGroups = groupSessionsByDate(sessions); const sessionGroups = groupSessionsByDate(sessions);
@@ -145,17 +166,21 @@ export function HistorySidebar({
{group.sessions.map((item) => { {group.sessions.map((item) => {
const label = getSessionListLabel(item); const label = getSessionListLabel(item);
const isPending = pendingDeleteId === item.id; const isPending = pendingDeleteId === item.id;
const isPendingSelect = pendingSelectId === item.id;
return ( return (
<li key={item.id} className={`sidebar-item-wrap${isPending ? ' sidebar-item-confirming' : ''}`}> <li key={item.id} className={`sidebar-item-wrap${isPending ? ' sidebar-item-confirming' : ''}`}>
<button <button
type="button" type="button"
className={`sidebar-item ${item.id === activeSessionId ? 'sidebar-item-active' : ''}`} className={`sidebar-item ${item.id === activeSessionId ? 'sidebar-item-active' : ''}${isPendingSelect ? ' sidebar-item-pending' : ''}`}
onClick={() => { if (!isPending) onSelect(item.id); }} onClick={() => handleSelectClick(item.id)}
> >
<span className="sidebar-item-title">{label}</span> <span className="sidebar-item-title">{label}</span>
<span className="sidebar-item-meta"> <span className="sidebar-item-meta">
{formatSessionTime(item.updated_at ?? item.created_at)} {formatSessionTime(item.updated_at ?? item.created_at)}
</span> </span>
{isPendingSelect && item.id !== activeSessionId ? (
<span className="sidebar-item-hint"></span>
) : null}
</button> </button>
{isPending ? ( {isPending ? (
<div className="sidebar-item-confirm"> <div className="sidebar-item-confirm">
+13 -11
View File
@@ -883,29 +883,28 @@ export function useTKMindChat(
setPendingTool(null); setPendingTool(null);
activeRequestId.current = null; activeRequestId.current = null;
const resumed = options?.skipResume
? (options.seedSession ?? null)
: await withTransientConnectRetry(() =>
resumeSession(sessionId, {
skipReconcile: options?.skipReconcile ?? false,
}),
);
if (token !== connectTokenRef.current) return;
const knownSession = sessionsRef.current.find((s) => s.id === sessionId); const knownSession = sessionsRef.current.find((s) => s.id === sessionId);
const hints = knownSession const hints = knownSession
? { messageCount: knownSession.message_count, updatedAt: knownSession.updated_at } ? { messageCount: knownSession.message_count, updatedAt: knownSession.updated_at }
: undefined; : undefined;
const { session: detail, messages: history, page } = await withTransientConnectRetry(() => const detailPromise = withTransientConnectRetry(() =>
loadSessionDetail(sessionId, hints, { loadSessionDetail(sessionId, hints, {
before: 0, before: 0,
limit: appConfig.sessionMessagePageSize, limit: appConfig.sessionMessagePageSize,
}), }),
); );
const resumedPromise = options?.skipResume
? Promise.resolve(options.seedSession ?? null)
: withTransientConnectRetry(() =>
resumeSession(sessionId, {
skipReconcile: options?.skipReconcile ?? false,
}),
);
const { session: detail, messages: history, page } = await detailPromise;
if (token !== connectTokenRef.current) return; if (token !== connectTokenRef.current) return;
writeStoredSessionId(userRef.current?.id, sessionId); writeStoredSessionId(userRef.current?.id, sessionId);
setSession({ ...detail, ...(resumed ?? {}), id: sessionId }); setSession((current) => (current?.id === sessionId ? { ...detail, ...current, id: sessionId } : { ...detail, id: sessionId }));
messagesRef.current = history; messagesRef.current = history;
messageHistoryLoadedCountRef.current = history.length; messageHistoryLoadedCountRef.current = history.length;
messageHistoryTotalRef.current = Math.max(Number(page.total ?? history.length), history.length); messageHistoryTotalRef.current = Math.max(Number(page.total ?? history.length), history.length);
@@ -913,6 +912,9 @@ export function useTKMindChat(
setMessageHistoryHasMore(messageHistoryHasMoreRef.current); setMessageHistoryHasMore(messageHistoryHasMoreRef.current);
setMessageHistoryTotal(messageHistoryTotalRef.current); setMessageHistoryTotal(messageHistoryTotalRef.current);
setMessages(history); setMessages(history);
const resumed = await resumedPromise;
if (token !== connectTokenRef.current) return;
setSession({ ...detail, ...(resumed ?? {}), id: sessionId });
setChatState('idle'); setChatState('idle');
setSessions((prev) => setSessions((prev) =>
prependUnique(prev, toSessionSummary({ ...detail, ...(resumed ?? {}), id: sessionId })), prependUnique(prev, toSessionSummary({ ...detail, ...(resumed ?? {}), id: sessionId })),