perf(app): keep warm workspace switching responsive (#3447)
* perf(app): reduce warm workspace switch work Retained workspaces avoided mounts but pane activity still rerendered the full composer, message input, and agent-control presentation. Keep the activity contract intact while moving focus-sensitive behavior behind small context consumers, and add a Playwright benchmark that measures rapid retained workspace switching on one browser clock. * perf(app): accelerate retained workspace switching Avoid repeated retained-stream layout reconciliation and unrelated workspace structure recomputation. Use the lightweight route transition while the host is already focused, while preserving targeted root POP_TO for returns from app-wide routes where it prevents duplicate hidden decks. * perf(app): defer composer focus during workspace switches * perf(app): retain recently used workspaces longer Keep up to ten workspace screens warm so normal multi-workspace navigation does not repeatedly rebuild recently used timelines. Inactive screens expire after ten minutes, while the active screen remains protected and capacity eviction stays least-recently-used. * fix(app): reconcile retained timeline geometry * fix(app): refresh retained reading position
This commit is contained in:
@@ -64,7 +64,11 @@ import { readMeasuredWidth } from "@/hooks/use-container-width";
|
||||
import { useToast } from "@/contexts/toast-context";
|
||||
import { toErrorMessage } from "@/utils/error-messages";
|
||||
import { showProviderNoticeToast } from "@/utils/provider-notice-toast";
|
||||
import { useAgentControlCommandCenterActions } from "@/command-center/agent-control-registration";
|
||||
import {
|
||||
useAgentControlCommandCenterActions,
|
||||
type AgentControlCommandCenterSource,
|
||||
} from "@/command-center/agent-control-registration";
|
||||
import { useComposerKeyboardScope } from "@/composer/keyboard-scope";
|
||||
import { isNative } from "@/constants/platform";
|
||||
import {
|
||||
resolveComposerControlDensity,
|
||||
@@ -154,11 +158,28 @@ export interface DraftAgentControlsProps {
|
||||
interface AgentControlsProps {
|
||||
agentId: string;
|
||||
serverId: string;
|
||||
isPaneFocused: boolean;
|
||||
onDropdownClose?: () => void;
|
||||
isCompactLayout?: boolean;
|
||||
}
|
||||
|
||||
function AgentControlCommandCenterRegistration({
|
||||
sourceId,
|
||||
enabled,
|
||||
controls,
|
||||
}: {
|
||||
sourceId: string;
|
||||
enabled: boolean;
|
||||
controls: AgentControlCommandCenterSource;
|
||||
}) {
|
||||
const { isActiveComposer } = useComposerKeyboardScope();
|
||||
useAgentControlCommandCenterActions({
|
||||
sourceId,
|
||||
enabled: enabled && isActiveComposer,
|
||||
controls,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
function findOptionLabel(
|
||||
options: AgentControlOption[] | undefined,
|
||||
selectedId: string | undefined,
|
||||
@@ -1477,7 +1498,6 @@ function ThinkingComboboxOption({
|
||||
export const AgentControls = memo(function AgentControls({
|
||||
agentId,
|
||||
serverId,
|
||||
isPaneFocused,
|
||||
onDropdownClose,
|
||||
isCompactLayout,
|
||||
}: AgentControlsProps) {
|
||||
@@ -1649,10 +1669,8 @@ export const AgentControls = memo(function AgentControls({
|
||||
[agentId, agentProvider, client, toast, updatePreferences],
|
||||
);
|
||||
|
||||
useAgentControlCommandCenterActions({
|
||||
sourceId: `agent:${serverId}:${agentId}`,
|
||||
enabled: isPaneFocused && Boolean(client),
|
||||
controls: {
|
||||
const commandCenterControls = useMemo<AgentControlCommandCenterSource>(
|
||||
() => ({
|
||||
serverId,
|
||||
ownerKey: agentId,
|
||||
provider: agentProvider,
|
||||
@@ -1673,8 +1691,31 @@ export const AgentControls = memo(function AgentControls({
|
||||
list: agent?.features,
|
||||
set: handleSetFeature,
|
||||
},
|
||||
},
|
||||
});
|
||||
}),
|
||||
[
|
||||
activeModelId,
|
||||
agent?.features,
|
||||
agentId,
|
||||
agentModelSelectorProviders,
|
||||
agentProvider,
|
||||
commandCenterModes,
|
||||
handleSelectCommandCenterModel,
|
||||
handleSelectThinkingOption,
|
||||
handleSetFeature,
|
||||
modeProviderDefinitions,
|
||||
modelSelection.selectedThinkingId,
|
||||
modelSelection.thinkingOptions,
|
||||
serverId,
|
||||
],
|
||||
);
|
||||
|
||||
const commandCenterRegistration = (
|
||||
<AgentControlCommandCenterRegistration
|
||||
sourceId={`agent:${serverId}:${agentId}`}
|
||||
enabled={Boolean(client)}
|
||||
controls={commandCenterControls}
|
||||
/>
|
||||
);
|
||||
|
||||
const handleModelSelectorOpen = useCallback(() => {
|
||||
refetchSnapshotIfStale(agentProvider);
|
||||
@@ -1692,30 +1733,33 @@ export const AgentControls = memo(function AgentControls({
|
||||
}
|
||||
|
||||
return (
|
||||
<ControlledAgentControls
|
||||
provider={agent.provider}
|
||||
modelSelectorProviders={agentModelSelectorProviders}
|
||||
modelOptions={modelOptions}
|
||||
selectedModelId={modelSelection.activeModelId ?? undefined}
|
||||
onSelectModel={handleSelectModel}
|
||||
agentProfiles={agentProfiles}
|
||||
onApplyAgentProfile={agentProfiles?.applyProfile}
|
||||
onEditAgentProfiles={handleEditAgentProfiles}
|
||||
thinkingOptions={thinkingOptions.length > 1 ? thinkingOptions : undefined}
|
||||
selectedThinkingOptionId={modelSelection.selectedThinkingId ?? undefined}
|
||||
onSelectThinkingOption={handleSelectThinkingOption}
|
||||
features={agent.features}
|
||||
onSetFeature={handleSetFeature}
|
||||
isModelLoading={snapshotIsLoading || selectedProviderIsLoading}
|
||||
onModelSelectorOpen={handleModelSelectorOpen}
|
||||
onRetryModelProvider={handleRetryModelProvider}
|
||||
isRetryingModelProvider={snapshotIsRefreshing}
|
||||
onDropdownClose={onDropdownClose}
|
||||
disabled={!client}
|
||||
modeControl={modeControl}
|
||||
modelSelectorServerId={serverId}
|
||||
isCompactLayout={isCompactLayout}
|
||||
/>
|
||||
<>
|
||||
{commandCenterRegistration}
|
||||
<ControlledAgentControls
|
||||
provider={agent.provider}
|
||||
modelSelectorProviders={agentModelSelectorProviders}
|
||||
modelOptions={modelOptions}
|
||||
selectedModelId={modelSelection.activeModelId ?? undefined}
|
||||
onSelectModel={handleSelectModel}
|
||||
agentProfiles={agentProfiles}
|
||||
onApplyAgentProfile={agentProfiles?.applyProfile}
|
||||
onEditAgentProfiles={handleEditAgentProfiles}
|
||||
thinkingOptions={thinkingOptions.length > 1 ? thinkingOptions : undefined}
|
||||
selectedThinkingOptionId={modelSelection.selectedThinkingId ?? undefined}
|
||||
onSelectThinkingOption={handleSelectThinkingOption}
|
||||
features={agent.features}
|
||||
onSetFeature={handleSetFeature}
|
||||
isModelLoading={snapshotIsLoading || selectedProviderIsLoading}
|
||||
onModelSelectorOpen={handleModelSelectorOpen}
|
||||
onRetryModelProvider={handleRetryModelProvider}
|
||||
isRetryingModelProvider={snapshotIsRefreshing}
|
||||
onDropdownClose={onDropdownClose}
|
||||
disabled={!client}
|
||||
modeControl={modeControl}
|
||||
modelSelectorServerId={serverId}
|
||||
isCompactLayout={isCompactLayout}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user