feat: add memory limits UI settings for messages in session
This commit is contained in:
@@ -5,7 +5,7 @@ import type { Message, Part } from "@opencode-ai/sdk/v2";
|
||||
import { opencodeClient } from "@/lib/opencode/client";
|
||||
import { isExecutionForkMetaText } from "@/lib/messages/executionMeta";
|
||||
import type { SessionMemoryState, MessageStreamLifecycle, AttachedFile } from "./types/sessionTypes";
|
||||
import { MEMORY_LIMITS } from "./types/sessionTypes";
|
||||
import { MEMORY_LIMITS, getMemoryLimits } from "./types/sessionTypes";
|
||||
import {
|
||||
touchStreamingLifecycle,
|
||||
removeLifecycleEntries,
|
||||
@@ -385,10 +385,12 @@ export const useMessageStore = create<MessageStore>()(
|
||||
pendingAssistantHeaderSessions: new Set(),
|
||||
pendingUserMessageMetaBySession: new Map(),
|
||||
|
||||
loadMessages: async (sessionId: string, limit: number = MEMORY_LIMITS.HISTORICAL_MESSAGES) => {
|
||||
loadMessages: async (sessionId: string, limit?: number) => {
|
||||
const memLimits = getMemoryLimits();
|
||||
const effectiveLimit = limit ?? memLimits.HISTORICAL_MESSAGES;
|
||||
const isStreaming = get().sessionMemoryState.get(sessionId)?.isStreaming;
|
||||
const targetLimit = isStreaming ? MEMORY_LIMITS.VIEWPORT_MESSAGES : limit;
|
||||
const fetchLimit = isStreaming ? undefined : targetLimit + MEMORY_LIMITS.FETCH_BUFFER;
|
||||
const targetLimit = isStreaming ? memLimits.VIEWPORT_MESSAGES : effectiveLimit;
|
||||
const fetchLimit = isStreaming ? undefined : targetLimit + memLimits.FETCH_BUFFER;
|
||||
const allMessages = await executeWithSessionDirectory(sessionId, () => opencodeClient.getSessionMessages(sessionId, fetchLimit));
|
||||
|
||||
// Filter out reverted messages first
|
||||
@@ -2227,10 +2229,11 @@ export const useMessageStore = create<MessageStore>()(
|
||||
};
|
||||
},
|
||||
|
||||
trimToViewportWindow: (sessionId: string, targetSize: number = MEMORY_LIMITS.VIEWPORT_MESSAGES, currentSessionId?: string) => {
|
||||
trimToViewportWindow: (sessionId: string, targetSize?: number, currentSessionId?: string) => {
|
||||
const effectiveTargetSize = targetSize ?? getMemoryLimits().VIEWPORT_MESSAGES;
|
||||
const state = get();
|
||||
const sessionMessages = state.messages.get(sessionId);
|
||||
if (!sessionMessages || sessionMessages.length <= targetSize) {
|
||||
if (!sessionMessages || sessionMessages.length <= effectiveTargetSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2246,11 +2249,11 @@ export const useMessageStore = create<MessageStore>()(
|
||||
}
|
||||
|
||||
const anchor = memoryState.viewportAnchor || sessionMessages.length - 1;
|
||||
let start = Math.max(0, anchor - Math.floor(targetSize / 2));
|
||||
const end = Math.min(sessionMessages.length, start + targetSize);
|
||||
let start = Math.max(0, anchor - Math.floor(effectiveTargetSize / 2));
|
||||
const end = Math.min(sessionMessages.length, start + effectiveTargetSize);
|
||||
|
||||
if (end === sessionMessages.length && end - start < targetSize) {
|
||||
start = Math.max(0, end - targetSize);
|
||||
if (end === sessionMessages.length && end - start < effectiveTargetSize) {
|
||||
start = Math.max(0, end - effectiveTargetSize);
|
||||
}
|
||||
|
||||
const trimmedMessages = sessionMessages.slice(start, end);
|
||||
|
||||
@@ -51,7 +51,8 @@ export interface SessionContextUsage {
|
||||
lastMessageId?: string;
|
||||
}
|
||||
|
||||
export const MEMORY_LIMITS = {
|
||||
// Default memory limits (can be overridden via settings)
|
||||
export const DEFAULT_MEMORY_LIMITS = {
|
||||
MAX_SESSIONS: 3,
|
||||
VIEWPORT_MESSAGES: 120,
|
||||
HISTORICAL_MESSAGES: 90,
|
||||
@@ -61,7 +62,35 @@ export const MEMORY_LIMITS = {
|
||||
ZOMBIE_TIMEOUT: 10 * 60 * 1000,
|
||||
} as const;
|
||||
|
||||
export const ACTIVE_SESSION_WINDOW = 180;
|
||||
export const DEFAULT_ACTIVE_SESSION_WINDOW = 180;
|
||||
|
||||
// Dynamic memory limits accessor - reads directly from UI store.
|
||||
// NOTE: do not use require() here (breaks in browser/desktop runtime bundles).
|
||||
import { useUIStore } from "../useUIStore";
|
||||
|
||||
export const getMemoryLimits = () => {
|
||||
const state = useUIStore.getState?.();
|
||||
if (!state) {
|
||||
return DEFAULT_MEMORY_LIMITS;
|
||||
}
|
||||
return {
|
||||
...DEFAULT_MEMORY_LIMITS,
|
||||
HISTORICAL_MESSAGES: state.memoryLimitHistorical ?? DEFAULT_MEMORY_LIMITS.HISTORICAL_MESSAGES,
|
||||
VIEWPORT_MESSAGES: state.memoryLimitViewport ?? DEFAULT_MEMORY_LIMITS.VIEWPORT_MESSAGES,
|
||||
};
|
||||
};
|
||||
|
||||
export const getActiveSessionWindow = () => {
|
||||
const state = useUIStore.getState?.();
|
||||
if (!state) {
|
||||
return DEFAULT_ACTIVE_SESSION_WINDOW;
|
||||
}
|
||||
return state.memoryLimitActiveSession ?? DEFAULT_ACTIVE_SESSION_WINDOW;
|
||||
};
|
||||
|
||||
// Legacy exports for backward compatibility (use getMemoryLimits() for dynamic values)
|
||||
export const MEMORY_LIMITS = DEFAULT_MEMORY_LIMITS;
|
||||
export const ACTIVE_SESSION_WINDOW = DEFAULT_ACTIVE_SESSION_WINDOW;
|
||||
|
||||
export type NewSessionDraftState = {
|
||||
open: boolean;
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { Session, Message, Part } from "@opencode-ai/sdk/v2";
|
||||
import type { PermissionRequest, PermissionResponse } from "@/types/permission";
|
||||
import type { QuestionRequest } from "@/types/question";
|
||||
import type { SessionStore, AttachedFile, EditPermissionMode } from "./types/sessionTypes";
|
||||
import { ACTIVE_SESSION_WINDOW, MEMORY_LIMITS } from "./types/sessionTypes";
|
||||
import { getActiveSessionWindow, getMemoryLimits } from "./types/sessionTypes";
|
||||
|
||||
import { useSessionStore as useSessionManagementStore } from "./sessionStore";
|
||||
import { useMessageStore } from "./messageStore";
|
||||
@@ -273,7 +273,7 @@ export const useSessionStore = create<SessionStore>()(
|
||||
get().updateViewportAnchor(previousSessionId, previousMessages.length - 1);
|
||||
}
|
||||
|
||||
get().trimToViewportWindow(previousSessionId, MEMORY_LIMITS.VIEWPORT_MESSAGES);
|
||||
get().trimToViewportWindow(previousSessionId, getMemoryLimits().VIEWPORT_MESSAGES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ export const useSessionStore = create<SessionStore>()(
|
||||
await get().loadMessages(id);
|
||||
}
|
||||
|
||||
get().trimToViewportWindow(id, ACTIVE_SESSION_WINDOW);
|
||||
get().trimToViewportWindow(id, getActiveSessionWindow());
|
||||
|
||||
// Analyze session messages to extract agent/model/variant choices
|
||||
// This ensures context is available even when ModelControls isn't mounted
|
||||
|
||||
@@ -43,6 +43,9 @@ interface UIStore {
|
||||
autoDeleteEnabled: boolean;
|
||||
autoDeleteAfterDays: number;
|
||||
autoDeleteLastRunAt: number | null;
|
||||
memoryLimitHistorical: number;
|
||||
memoryLimitViewport: number;
|
||||
memoryLimitActiveSession: number;
|
||||
|
||||
toolCallExpansion: 'collapsed' | 'activity' | 'detailed';
|
||||
fontSize: number;
|
||||
@@ -87,6 +90,9 @@ interface UIStore {
|
||||
setAutoDeleteEnabled: (value: boolean) => void;
|
||||
setAutoDeleteAfterDays: (days: number) => void;
|
||||
setAutoDeleteLastRunAt: (timestamp: number | null) => void;
|
||||
setMemoryLimitHistorical: (value: number) => void;
|
||||
setMemoryLimitViewport: (value: number) => void;
|
||||
setMemoryLimitActiveSession: (value: number) => void;
|
||||
setToolCallExpansion: (value: 'collapsed' | 'activity' | 'detailed') => void;
|
||||
setFontSize: (size: number) => void;
|
||||
setPadding: (size: number) => void;
|
||||
@@ -141,6 +147,9 @@ export const useUIStore = create<UIStore>()(
|
||||
autoDeleteEnabled: false,
|
||||
autoDeleteAfterDays: 30,
|
||||
autoDeleteLastRunAt: null,
|
||||
memoryLimitHistorical: 90,
|
||||
memoryLimitViewport: 120,
|
||||
memoryLimitActiveSession: 180,
|
||||
toolCallExpansion: 'collapsed',
|
||||
fontSize: 100,
|
||||
padding: 100,
|
||||
@@ -296,6 +305,21 @@ export const useUIStore = create<UIStore>()(
|
||||
set({ autoDeleteLastRunAt: timestamp });
|
||||
},
|
||||
|
||||
setMemoryLimitHistorical: (value) => {
|
||||
const clamped = Math.max(10, Math.min(500, Math.round(value)));
|
||||
set({ memoryLimitHistorical: clamped });
|
||||
},
|
||||
|
||||
setMemoryLimitViewport: (value) => {
|
||||
const clamped = Math.max(20, Math.min(500, Math.round(value)));
|
||||
set({ memoryLimitViewport: clamped });
|
||||
},
|
||||
|
||||
setMemoryLimitActiveSession: (value) => {
|
||||
const clamped = Math.max(30, Math.min(1000, Math.round(value)));
|
||||
set({ memoryLimitActiveSession: clamped });
|
||||
},
|
||||
|
||||
setToolCallExpansion: (value) => {
|
||||
set({ toolCallExpansion: value });
|
||||
},
|
||||
@@ -527,6 +551,9 @@ export const useUIStore = create<UIStore>()(
|
||||
autoDeleteEnabled: state.autoDeleteEnabled,
|
||||
autoDeleteAfterDays: state.autoDeleteAfterDays,
|
||||
autoDeleteLastRunAt: state.autoDeleteLastRunAt,
|
||||
memoryLimitHistorical: state.memoryLimitHistorical,
|
||||
memoryLimitViewport: state.memoryLimitViewport,
|
||||
memoryLimitActiveSession: state.memoryLimitActiveSession,
|
||||
toolCallExpansion: state.toolCallExpansion,
|
||||
fontSize: state.fontSize,
|
||||
padding: state.padding,
|
||||
|
||||
Reference in New Issue
Block a user