feat: add active turn anchor management for improved scroll position handling
This commit is contained in:
@@ -361,6 +361,8 @@ interface MessageActions {
|
||||
updateMessageInfo: (sessionId: string, messageId: string, messageInfo: any) => void;
|
||||
syncMessages: (sessionId: string, messages: { info: Message; parts: Part[] }[]) => void;
|
||||
updateViewportAnchor: (sessionId: string, anchor: number) => void;
|
||||
updateActiveTurnAnchor: (sessionId: string, anchorId: string | null, spacerHeight: number) => void;
|
||||
getActiveTurnAnchor: (sessionId: string) => { anchorId: string | null; spacerHeight: number } | null;
|
||||
trimToViewportWindow: (sessionId: string, targetSize?: number, currentSessionId?: string) => void;
|
||||
evictLeastRecentlyUsed: (currentSessionId?: string) => void;
|
||||
loadMoreMessages: (sessionId: string, direction: "up" | "down") => Promise<void>;
|
||||
@@ -479,6 +481,7 @@ export const useMessageStore = create<MessageStore>()(
|
||||
const newMemoryState = new Map(state.sessionMemoryState);
|
||||
const previousMemoryState = state.sessionMemoryState.get(sessionId);
|
||||
newMemoryState.set(sessionId, {
|
||||
...previousMemoryState,
|
||||
viewportAnchor: mergedMessages.length - 1,
|
||||
isStreaming: false,
|
||||
lastAccessedAt: Date.now(),
|
||||
@@ -2202,6 +2205,34 @@ export const useMessageStore = create<MessageStore>()(
|
||||
});
|
||||
},
|
||||
|
||||
updateActiveTurnAnchor: (sessionId: string, anchorId: string | null, spacerHeight: number) => {
|
||||
set((state) => {
|
||||
const memoryState = state.sessionMemoryState.get(sessionId) || {
|
||||
viewportAnchor: 0,
|
||||
isStreaming: false,
|
||||
lastAccessedAt: Date.now(),
|
||||
backgroundMessageCount: 0,
|
||||
};
|
||||
|
||||
const newMemoryState = new Map(state.sessionMemoryState);
|
||||
newMemoryState.set(sessionId, {
|
||||
...memoryState,
|
||||
activeTurnAnchorId: anchorId ?? undefined,
|
||||
activeTurnSpacerHeight: spacerHeight,
|
||||
});
|
||||
return { sessionMemoryState: newMemoryState };
|
||||
});
|
||||
},
|
||||
|
||||
getActiveTurnAnchor: (sessionId: string) => {
|
||||
const memoryState = get().sessionMemoryState.get(sessionId);
|
||||
if (!memoryState) return null;
|
||||
return {
|
||||
anchorId: memoryState.activeTurnAnchorId ?? null,
|
||||
spacerHeight: memoryState.activeTurnSpacerHeight ?? 0,
|
||||
};
|
||||
},
|
||||
|
||||
trimToViewportWindow: (sessionId: string, targetSize: number = MEMORY_LIMITS.VIEWPORT_MESSAGES, currentSessionId?: string) => {
|
||||
const state = get();
|
||||
const sessionMessages = state.messages.get(sessionId);
|
||||
|
||||
@@ -34,6 +34,10 @@ export interface SessionMemoryState {
|
||||
hasMoreAbove?: boolean;
|
||||
trimmedHeadMaxId?: string;
|
||||
streamingCooldownUntil?: number;
|
||||
/** Message ID of the user's active turn anchor (for scroll position preservation) */
|
||||
activeTurnAnchorId?: string;
|
||||
/** Height of the spacer below messages for active turn positioning */
|
||||
activeTurnSpacerHeight?: number;
|
||||
}
|
||||
|
||||
export interface SessionContextUsage {
|
||||
@@ -151,6 +155,8 @@ export interface SessionStore {
|
||||
clearAttachedFiles: () => void;
|
||||
|
||||
updateViewportAnchor: (sessionId: string, anchor: number) => void;
|
||||
updateActiveTurnAnchor: (sessionId: string, anchorId: string | null, spacerHeight: number) => void;
|
||||
getActiveTurnAnchor: (sessionId: string) => { anchorId: string | null; spacerHeight: number } | null;
|
||||
trimToViewportWindow: (sessionId: string, targetSize?: number) => void;
|
||||
evictLeastRecentlyUsed: () => void;
|
||||
loadMoreMessages: (sessionId: string, direction: "up" | "down") => Promise<void>;
|
||||
|
||||
@@ -442,6 +442,8 @@ export const useSessionStore = create<SessionStore>()(
|
||||
clearAttachedFiles: () => useFileStore.getState().clearAttachedFiles(),
|
||||
|
||||
updateViewportAnchor: (sessionId: string, anchor: number) => useMessageStore.getState().updateViewportAnchor(sessionId, anchor),
|
||||
updateActiveTurnAnchor: (sessionId: string, anchorId: string | null, spacerHeight: number) => useMessageStore.getState().updateActiveTurnAnchor(sessionId, anchorId, spacerHeight),
|
||||
getActiveTurnAnchor: (sessionId: string) => useMessageStore.getState().getActiveTurnAnchor(sessionId),
|
||||
trimToViewportWindow: (sessionId: string, targetSize?: number) => {
|
||||
const currentSessionId = useSessionManagementStore.getState().currentSessionId;
|
||||
return useMessageStore.getState().trimToViewportWindow(sessionId, targetSize, currentSessionId || undefined);
|
||||
|
||||
Reference in New Issue
Block a user