perf(ui): improve mobile session switching
Treat the mobile web surface as a constrained runtime so sync loads smaller message pages, keeps fewer warm session caches, and evicts heavy inactive sessions instead of retaining them across switches. Limit mobile message-record and turn-model caches to reduce memory pressure on phones while preserving bounded initial page expansion for large final turns. Split the mobile session status bar so the collapsed state avoids subscribing to the full session/status list; the expensive grouping work now only mounts for the expanded list. Verified with bun run type-check and bun run lint.
This commit is contained in:
@@ -7,6 +7,7 @@ import { useStore } from "zustand"
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk/v2/client"
|
||||
import { createEventPipeline } from "./event-pipeline"
|
||||
import { isVSCodeRuntime } from "@/lib/desktop"
|
||||
import { isMobileSurfaceRuntime } from "@/lib/runtimeSurface"
|
||||
import { reduceGlobalEvent, applyGlobalProject, applyDirectoryEvent } from "./event-reducer"
|
||||
import { useGlobalSyncStore, type GlobalSyncStore } from "./global-sync-store"
|
||||
import { ChildStoreManager, type DirectoryStore } from "./child-store"
|
||||
@@ -113,6 +114,35 @@ export function useAllSessionStatuses(): Record<string, SessionStatus> {
|
||||
)
|
||||
}
|
||||
|
||||
type LiveSessionStatusCounts = {
|
||||
running: number
|
||||
}
|
||||
|
||||
const EMPTY_LIVE_SESSION_STATUS_COUNTS: LiveSessionStatusCounts = { running: 0 }
|
||||
|
||||
const isRunningSessionStatus = (status: SessionStatus | undefined): boolean => (
|
||||
status?.type === "busy" || status?.type === "retry"
|
||||
)
|
||||
|
||||
const areLiveSessionStatusCountsEquivalent = (left: LiveSessionStatusCounts, right: LiveSessionStatusCounts): boolean => (
|
||||
left.running === right.running
|
||||
)
|
||||
|
||||
export function useLiveSessionStatusCounts(): LiveSessionStatusCounts {
|
||||
return useLiveSyncSelector(
|
||||
useCallback((states) => {
|
||||
let running = 0
|
||||
for (const state of states) {
|
||||
for (const status of Object.values(state.session_status ?? {})) {
|
||||
if (isRunningSessionStatus(status)) running += 1
|
||||
}
|
||||
}
|
||||
return running === 0 ? EMPTY_LIVE_SESSION_STATUS_COUNTS : { running }
|
||||
}, []),
|
||||
areLiveSessionStatusCountsEquivalent,
|
||||
)
|
||||
}
|
||||
|
||||
export function useAllLiveSessions(): Session[] {
|
||||
return useLiveSyncSelector(
|
||||
useCallback((states) => aggregateLiveSessions(states), []),
|
||||
@@ -2012,6 +2042,8 @@ type SessionMessageRecordsSnapshot = {
|
||||
const SESSION_MESSAGE_RECORDS_CACHE_MAX = 40
|
||||
const VSCODE_SESSION_MESSAGE_RECORDS_CACHE_MAX = 4
|
||||
const VSCODE_SESSION_MESSAGE_RECORDS_CACHE_MAX_MESSAGES = 30
|
||||
const MOBILE_SESSION_MESSAGE_RECORDS_CACHE_MAX = 4
|
||||
const MOBILE_SESSION_MESSAGE_RECORDS_CACHE_MAX_MESSAGES = 30
|
||||
const sessionMessageRecordsCache = new WeakMap<StoreApi<DirectoryStore>, Map<string, SessionMessageRecordsSnapshot>>()
|
||||
|
||||
const getSessionMessageRecordsCacheKey = (sessionID: string, suspendPartUpdates: boolean): string => (
|
||||
@@ -2049,13 +2081,22 @@ const rememberSessionMessageRecordsSnapshot = (
|
||||
if (!snapshot.sessionID) return
|
||||
const cache = getSessionMessageRecordsCache(store)
|
||||
const key = getSessionMessageRecordsCacheKey(snapshot.sessionID, snapshot.suspendPartUpdates)
|
||||
if (isVSCodeRuntime() && snapshot.list.length > VSCODE_SESSION_MESSAGE_RECORDS_CACHE_MAX_MESSAGES) {
|
||||
const constrainedMaxMessages = isVSCodeRuntime()
|
||||
? VSCODE_SESSION_MESSAGE_RECORDS_CACHE_MAX_MESSAGES
|
||||
: isMobileSurfaceRuntime()
|
||||
? MOBILE_SESSION_MESSAGE_RECORDS_CACHE_MAX_MESSAGES
|
||||
: null
|
||||
if (constrainedMaxMessages !== null && snapshot.list.length > constrainedMaxMessages) {
|
||||
cache.delete(key)
|
||||
return
|
||||
}
|
||||
cache.delete(key)
|
||||
cache.set(key, snapshot)
|
||||
const max = isVSCodeRuntime() ? VSCODE_SESSION_MESSAGE_RECORDS_CACHE_MAX : SESSION_MESSAGE_RECORDS_CACHE_MAX
|
||||
const max = isVSCodeRuntime()
|
||||
? VSCODE_SESSION_MESSAGE_RECORDS_CACHE_MAX
|
||||
: isMobileSurfaceRuntime()
|
||||
? MOBILE_SESSION_MESSAGE_RECORDS_CACHE_MAX
|
||||
: SESSION_MESSAGE_RECORDS_CACHE_MAX
|
||||
while (cache.size > max) {
|
||||
const oldest = cache.keys().next().value
|
||||
if (typeof oldest !== "string") break
|
||||
|
||||
Reference in New Issue
Block a user