mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
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:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user