📳 refactor: Optimize Model Selector (#11787)

- Introduced a new `EndpointMenuContent` component to lazily render endpoint submenu content, improving performance by deferring expensive model-list rendering until the submenu is mounted.
- Refactored `EndpointItem` to utilize the new component, simplifying the code and enhancing readability.
- Removed redundant filtering logic and model specifications handling from `EndpointItem`, centralizing it within `EndpointMenuContent` for better maintainability.
This commit is contained in:
Danny Avila 2026-02-13 22:46:14 -05:00 committed by GitHub
parent dc489e7b25
commit 6cc6ee3207
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -80,12 +80,76 @@ const SettingsButton = ({
);
};
/**
* Lazily-rendered content for an endpoint submenu. By extracting this into a
* separate component, the expensive model-list rendering (and per-item hooks
* such as MutationObservers in EndpointModelItem) only runs when the submenu
* is actually mounted which Ariakit defers via `unmountOnHide`.
*/
function EndpointMenuContent({
endpoint,
endpointIndex,
}: {
endpoint: Endpoint;
endpointIndex: number;
}) {
const localize = useLocalize();
const { agentsMap, assistantsMap, modelSpecs, selectedValues, endpointSearchValues } =
useModelSelectorContext();
const { model: selectedModel, modelSpec: selectedSpec } = selectedValues;
const searchValue = endpointSearchValues[endpoint.value] || '';
const endpointSpecs = useMemo(() => {
if (!modelSpecs || !modelSpecs.length) {
return [];
}
return modelSpecs.filter((spec: TModelSpec) => spec.group === endpoint.value);
}, [modelSpecs, endpoint.value]);
if (isAssistantsEndpoint(endpoint.value) && endpoint.models === undefined) {
return (
<div
className="flex items-center justify-center p-2"
role="status"
aria-label={localize('com_ui_loading')}
>
<Spinner aria-hidden="true" />
</div>
);
}
const filteredModels = searchValue
? filterModels(
endpoint,
(endpoint.models || []).map((model) => model.name),
searchValue,
agentsMap,
assistantsMap,
)
: null;
return (
<>
{endpointSpecs.map((spec: TModelSpec) => (
<ModelSpecItem key={spec.name} spec={spec} isSelected={selectedSpec === spec.name} />
))}
{filteredModels
? renderEndpointModels(
endpoint,
endpoint.models || [],
selectedModel,
filteredModels,
endpointIndex,
)
: endpoint.models &&
renderEndpointModels(endpoint, endpoint.models, selectedModel, undefined, endpointIndex)}
</>
);
}
export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
const localize = useLocalize();
const {
agentsMap,
assistantsMap,
modelSpecs,
selectedValues,
handleOpenKeyDialog,
handleSelectEndpoint,
@ -93,19 +157,7 @@ export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
setEndpointSearchValue,
endpointRequiresUserKey,
} = useModelSelectorContext();
const {
model: selectedModel,
endpoint: selectedEndpoint,
modelSpec: selectedSpec,
} = selectedValues;
// Filter modelSpecs for this endpoint (by group matching endpoint value)
const endpointSpecs = useMemo(() => {
if (!modelSpecs || !modelSpecs.length) {
return [];
}
return modelSpecs.filter((spec: TModelSpec) => spec.group === endpoint.value);
}, [modelSpecs, endpoint.value]);
const { endpoint: selectedEndpoint } = selectedValues;
const searchValue = endpointSearchValues[endpoint.value] || '';
const isUserProvided = useMemo(
@ -130,15 +182,6 @@ export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
const isEndpointSelected = selectedEndpoint === endpoint.value;
if (endpoint.hasModels) {
const filteredModels = searchValue
? filterModels(
endpoint,
(endpoint.models || []).map((model) => model.name),
searchValue,
agentsMap,
assistantsMap,
)
: null;
const placeholder =
isAgentsEndpoint(endpoint.value) || isAssistantsEndpoint(endpoint.value)
? localize('com_endpoint_search_var', { 0: endpoint.label })
@ -147,7 +190,6 @@ export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
<Menu
id={`endpoint-${endpoint.value}-menu`}
key={`endpoint-${endpoint.value}-item`}
defaultOpen={endpoint.value === selectedEndpoint}
searchValue={searchValue}
onSearch={(value) => setEndpointSearchValue(endpoint.value, value)}
combobox={<input placeholder=" " />}
@ -170,39 +212,7 @@ export function EndpointItem({ endpoint, endpointIndex }: EndpointItemProps) {
</div>
}
>
{isAssistantsEndpoint(endpoint.value) && endpoint.models === undefined ? (
<div
className="flex items-center justify-center p-2"
role="status"
aria-label={localize('com_ui_loading')}
>
<Spinner aria-hidden="true" />
</div>
) : (
<>
{/* Render modelSpecs for this endpoint */}
{endpointSpecs.map((spec: TModelSpec) => (
<ModelSpecItem key={spec.name} spec={spec} isSelected={selectedSpec === spec.name} />
))}
{/* Render endpoint models */}
{filteredModels
? renderEndpointModels(
endpoint,
endpoint.models || [],
selectedModel,
filteredModels,
endpointIndex,
)
: endpoint.models &&
renderEndpointModels(
endpoint,
endpoint.models,
selectedModel,
undefined,
endpointIndex,
)}
</>
)}
<EndpointMenuContent endpoint={endpoint} endpointIndex={endpointIndex} />
</Menu>
);
} else {