perf(native-chat): memoize file-link context per chat on its resolver inputs (#34755)

* perf(native-chat): memoize file-link context per chat on its resolver inputs

Every mounted chat (hidden ones included) re-resolved its directory and
runtime owner on every store write. Reuse the context until an input the
resolvers read changes.

* docs(native-chat): scope the file-link input completeness comment
This commit is contained in:
Neil
2026-10-27 22:51:41 -07:00
committed by GitHub
parent b62f9bf624
commit 766462be18
2 changed files with 64 additions and 3 deletions
@@ -5,6 +5,7 @@ import { folderWorkspaceKey } from '../../../../shared/workspace-scope'
import { FLOATING_TERMINAL_WORKTREE_ID, getDefaultSettings } from '../../../../shared/constants'
import { createNativeChatFileHref } from '../../../../shared/native-chat-href-routing'
import {
createNativeChatFileLinkContextSelector,
findNativeChatTabOwnerWorktreeId,
resolveNativeChatFileLink,
resolveNativeChatFileLinkContext,
@@ -144,6 +145,21 @@ describe('resolveNativeChatFileLinkContext', () => {
})
})
describe('createNativeChatFileLinkContextSelector', () => {
it('reuses the context across unrelated writes and re-resolves when a route input changes', () => {
const select = createNativeChatFileLinkContextSelector('tab-1')
const base = state()
const first = select(base)
expect(select({ ...base })).toBe(first)
const moved = select({
...base,
worktreesByRepo: { repo: [worktreeFixture('wt-1', '/repo/moved')] }
})
expect(moved?.worktreePath).toBe('/repo/moved')
})
})
describe('floating workspace native chat', () => {
const floatingTab = {
id: 'floating-chat-1',
@@ -12,7 +12,11 @@ import {
} from '../../../../shared/explicit-file-link-target'
import { runtimeEnvironmentIdOrLocalUnlessTwin } from '@/lib/worktree-runtime-owner'
import type { AppState } from '@/store/types'
import { resolveNativeChatTabDirectory } from './native-chat-tab-directory'
import type { WorktreeRuntimeOwnerState } from '@/lib/worktree-runtime-owner-state'
import {
resolveNativeChatTabDirectory,
type NativeChatTabDirectoryState
} from './native-chat-tab-directory'
export type NativeChatFileLinkContext = {
worktreeId: string
@@ -87,10 +91,51 @@ export function resolveNativeChatFileLinkContext(
)
}
type FileLinkContextInputState = WorktreeRuntimeOwnerState & NativeChatTabDirectoryState
// Every field the directory and owner resolvers read.
const FILE_LINK_CONTEXT_INPUT_KEYS = [
'repos',
'settings',
'worktreesByRepo',
'detectedWorktreesByRepo',
'folderWorkspaces',
'projectGroups',
'restoredRuntimeHostIdByWorkspaceSessionKey',
'activeWorktreeId',
'activeWorkspaceExecutionHostId',
'runtimeEnvironments',
'runtimeEnvironmentCatalogHydrated',
'removedRuntimeEnvironmentIds',
'floatingWorkspacePath',
'structuredSessionLaunchDirectoryByTabId'
] as const satisfies readonly (keyof FileLinkContextInputState)[]
type UnlistedInput = Exclude<
keyof FileLinkContextInputState,
(typeof FILE_LINK_CONTEXT_INPUT_KEYS)[number] | 'unifiedTabsByWorktree'
>
// Fails to compile when either state type gains a key not listed above; deeper resolver types are not checked.
const allInputsListed: [UnlistedInput] extends [never] ? true : UnlistedInput = true
void allInputsListed
export function createNativeChatFileLinkContextSelector(tabId: string) {
const selectOwner = createNativeChatTabOwnerSelector(tabId)
return (state: NativeChatFileLinkState) =>
resolveNativeChatFileLinkContextForOwner(state, tabId, selectOwner(state))
let inputs: unknown[] | null = null
let context: NativeChatFileLinkContext | null = null
// Hidden chats still subscribe, so unrelated store writes must not re-resolve directory/owner.
return (state: NativeChatFileLinkState & Partial<FileLinkContextInputState>) => {
const owner = selectOwner(state)
const next = [
owner,
state.unifiedTabsByWorktree,
...FILE_LINK_CONTEXT_INPUT_KEYS.map((key) => state[key])
]
if (!inputs || next.some((input, index) => input !== inputs?.[index])) {
inputs = next
context = resolveNativeChatFileLinkContextForOwner(state, tabId, owner)
}
return context
}
}
export function resolveNativeChatFileLinkContextForOwner(