perf: overhaul session loading, caching, and runtime isolation (#2360)

Improve OpenChamber responsiveness under large session workloads while fixing
cache, synchronization, and persistence correctness across runtimes, projects,
directories, and worktrees.

- prioritize selected and visible sessions during bootstrap and defer
  non-critical enrichment work
- reduce redundant message loading, event processing, store publication, and
  hidden sidebar work
- prevent stale session and message requests from overwriting newer
  authoritative state
- preserve existing data when authoritative fetches fail instead of treating
  failures as successful empty responses
- scope session materialization, messages, drafts, queues, todos, pins,
  permissions, folders, tabs, Git state, and pull request data by runtime and
  directory identity
- harden runtime switching, reconnect, cleanup, mutation reconciliation, and
  persisted-state ordering
- preserve live subagent Task linkage when metadata arrives after an older
  message request or while streaming parts are suspended
- coalesce overlapping tail refreshes without losing newer refresh demand
- improve cold-session loading by moving deferrable work out of the critical
  bootstrap path
- isolate URL authentication, mobile credentials, native secrets, and other
  runtime-owned state across endpoint changes
- bound long-lived caches and remove avoidable allocations from event and
  rendering hot paths
- limit virtualization to archive collections where it improves rendering
  without disrupting active sidebar layout
- stabilize session folders, pin ordering, expanded state, and persisted
  sidebar behavior
- open skill files through the same secure editor and outside-workspace grant
  flow used by file navigation, including worktree sessions
- expand regression coverage for stale completions, runtime collisions,
  reconnect behavior, persistence races, authoritative empty results, and
  subagent refresh ordering
- document the updated synchronization, cache ownership, performance, and
  runtime-isolation invariants
This commit is contained in:
Bohdan Triapitsyn
2026-07-21 20:52:20 +03:00
committed by GitHub
parent 485efc7117
commit 85400459e9
197 changed files with 10835 additions and 3400 deletions
@@ -1,6 +1,11 @@
import { describe, expect, test } from "bun:test"
import type { Message, Part } from "@opencode-ai/sdk/v2/client"
import { getSessionMaterializationStatus, materializeSessionSnapshots } from "../materialization"
import {
getSessionMaterializationRequestKey,
getSessionMaterializationStatus,
isSessionMaterializationStillNeeded,
materializeSessionSnapshots,
} from "../materialization"
function message(id: string, sessionID = "ses_1"): Message {
return { id, sessionID, role: "assistant", time: { created: 1 } } as Message
@@ -14,6 +19,13 @@ function part(id: string, messageID: string, type = "text", text = id): Part {
return { id, messageID, sessionID: "ses_1", type, text } as Part
}
describe("getSessionMaterializationRequestKey", () => {
test("isolates the same directory and session identity across runtimes", () => {
expect(getSessionMaterializationRequestKey("runtime-a", "/repo", "ses_1"))
.not.toBe(getSessionMaterializationRequestKey("runtime-b", "/repo", "ses_1"))
})
})
describe("materializeSessionSnapshots", () => {
test("marks an empty successful page as materialized", () => {
const result = materializeSessionSnapshots(
@@ -182,3 +194,47 @@ describe("getSessionMaterializationStatus", () => {
})
})
})
describe("isSessionMaterializationStillNeeded", () => {
test("skips empty-assistant recovery after a part bucket arrives", () => {
const state = { message: { ses_1: [message("msg_1")] }, part: { msg_1: [part("prt_1", "msg_1")] } }
expect(isSessionMaterializationStillNeeded(state, "ses_1", {
reason: "empty-assistant-message",
messageID: "msg_1",
})).toBe(false)
})
test("treats an explicit empty part bucket as authoritative", () => {
const state = { message: { ses_1: [message("msg_1")] }, part: { msg_1: [] } }
expect(isSessionMaterializationStillNeeded(state, "ses_1", {
reason: "empty-assistant-message",
messageID: "msg_1",
})).toBe(false)
})
test("skips missing-message and missing-part recovery after ordered events repair state", () => {
const state = { message: { ses_1: [message("msg_1")] }, part: { msg_1: [part("prt_1", "msg_1")] } }
expect(isSessionMaterializationStillNeeded(state, "ses_1", {
reason: "missing-owning-message",
messageID: "msg_1",
})).toBe(false)
expect(isSessionMaterializationStillNeeded(state, "ses_1", {
reason: "missing-delta-part",
messageID: "msg_1",
partID: "prt_1",
})).toBe(false)
})
test("keeps recovery active while the requested entity is still missing", () => {
const state = { message: { ses_1: [message("msg_1")] }, part: {} }
expect(isSessionMaterializationStillNeeded(state, "ses_1", {
reason: "orphan-delta",
messageID: "msg_1",
partID: "prt_1",
})).toBe(true)
})
})
@@ -1,32 +0,0 @@
import { describe, expect, test } from "bun:test"
import { shouldSkipSessionPrefetch } from "../session-prefetch-cache"
describe("shouldSkipSessionPrefetch", () => {
test("does not skip when only metadata exists without cached messages", () => {
expect(shouldSkipSessionPrefetch({
hasMessages: false,
info: { limit: 200, complete: true, at: 1_000 },
pageSize: 200,
now: 1_001,
})).toBe(false)
})
test("does not skip a larger fetch when only a smaller partial prefetch is cached", () => {
expect(shouldSkipSessionPrefetch({
hasMessages: true,
info: { limit: 50, complete: false, at: 1_000 },
pageSize: 200,
now: 1_001,
})).toBe(false)
})
test("still skips a recent partial prefetch when cached coverage matches the request", () => {
expect(shouldSkipSessionPrefetch({
hasMessages: true,
info: { limit: 200, complete: false, at: 1_000 },
pageSize: 200,
now: 1_001,
})).toBe(true)
})
})
@@ -3,8 +3,14 @@ import type { Event, Session } from "@opencode-ai/sdk/v2/client"
let currentSessions: Session[] = []
const upsertedSessions: Session[] = []
const removedSessionIds: string[] = []
let runtimeKey = "runtime-a"
let runtimeWillChange: (() => void) | null = null
mock.module("@/stores/useGlobalSessionsStore", () => ({
isGlobalSessionRecencyOnlyUpdate: (existing: Session, incoming: Session) => (
existing.title === incoming.title && existing.time?.updated !== incoming.time?.updated
),
useGlobalSessionsStore: {
getState: () => ({
activeSessions: currentSessions,
@@ -12,9 +18,22 @@ mock.module("@/stores/useGlobalSessionsStore", () => ({
upsertSession: (session: Session) => {
upsertedSessions.push(session)
},
upsertSessions: (sessions: Session[]) => {
upsertedSessions.push(...sessions)
},
removeSessions: (ids: string[]) => {
removedSessionIds.push(...ids)
},
}),
},
}))
mock.module("@/lib/runtime-switch", () => ({
getRuntimeKey: () => runtimeKey,
subscribeRuntimeEndpointWillChange: (callback: () => void) => {
runtimeWillChange = callback
return () => undefined
},
}))
import { applySessionEventToGlobalSessions } from "../session-event-router"
const buildSession = (title: string, time: Session["time"]): Session => ({
@@ -30,10 +49,23 @@ const buildEvent = (session: Session): Event => ({
},
} as Event)
const buildDeleteEvent = (sessionId: string): Event => ({
type: "session.deleted",
properties: { sessionID: sessionId },
} as Event)
const buildLifecycleEvent = (type: "session.idle" | "session.error", sessionId: string): Event => ({
type,
properties: { sessionID: sessionId },
} as Event)
describe("applySessionEventToGlobalSessions", () => {
beforeEach(() => {
runtimeWillChange?.()
runtimeKey = "runtime-a"
currentSessions = []
upsertedSessions.length = 0
removedSessionIds.length = 0
})
test("skips stale global session.updated echoes after a newer rename", () => {
@@ -43,4 +75,45 @@ describe("applySessionEventToGlobalSessions", () => {
expect(upsertedSessions).toEqual([])
})
test("commits only the latest recency update when a session becomes idle", () => {
currentSessions = [buildSession("Initial", { created: 1, updated: 10 })]
applySessionEventToGlobalSessions(buildEvent(buildSession("Initial", { created: 1, updated: 20 })))
applySessionEventToGlobalSessions(buildEvent(buildSession("Initial", { created: 1, updated: 30 })))
expect(upsertedSessions).toEqual([])
applySessionEventToGlobalSessions(buildLifecycleEvent("session.idle", "ses_1"))
expect(upsertedSessions.map((session) => session.time.updated)).toEqual([30])
})
test("applies substantive session updates immediately", () => {
currentSessions = [buildSession("Initial", { created: 1, updated: 10 })]
applySessionEventToGlobalSessions(buildEvent(buildSession("Renamed", { created: 1, updated: 20 })))
expect(upsertedSessions.map((session) => session.title)).toEqual(["Renamed"])
})
test("cancels a pending global update when the session is deleted", () => {
currentSessions = [buildSession("Initial", { created: 1, updated: 10 })]
applySessionEventToGlobalSessions(buildEvent(buildSession("Initial", { created: 1, updated: 20 })))
applySessionEventToGlobalSessions(buildDeleteEvent("ses_1"))
applySessionEventToGlobalSessions(buildLifecycleEvent("session.idle", "ses_1"))
expect(upsertedSessions).toEqual([])
expect(removedSessionIds).toEqual(["ses_1"])
})
test("discards pending global updates when the runtime changes", () => {
currentSessions = [buildSession("Initial", { created: 1, updated: 10 })]
applySessionEventToGlobalSessions(buildEvent(buildSession("Initial", { created: 1, updated: 20 })))
runtimeKey = "runtime-b"
runtimeWillChange?.()
applySessionEventToGlobalSessions(buildLifecycleEvent("session.idle", "ses_1"))
expect(upsertedSessions).toEqual([])
})
})