perf(ui): memoize getAllPresets to prevent re-parsing on every render

This commit is contained in:
Tin Chi Lo 2026-07-31 00:10:19 -07:00
parent bc1e0d92c2
commit 8b89dcf9c0
2 changed files with 143 additions and 21 deletions

View file

@ -62,6 +62,37 @@ vi.mock("./build_complexity_router_config", async (importOriginal) => {
return { ...actual, getMissingTiersError: vi.fn(actual.getMissingTiersError) };
});
// Real bundled presets carry no deliberately-falsy fields, so a synthetic preset is appended to
// prove prefill preserves a 0 match threshold and an empty escalation list (a preset switching
// escalation off) instead of overwriting them with the create-form defaults. Defined via
// vi.hoisted so it exists when the hoisted vi.mock factory below references it.
const { FALSY_PRESET } = vi.hoisted(() => ({
FALSY_PRESET: {
key: "falsy_family",
label: "Falsy Family",
description: "Preset that deliberately disables escalation and pins a zero match threshold",
complexity_router_config: {
tiers: { SIMPLE: ["gpt-5-nano"], MEDIUM: ["gpt-5-mini"], COMPLEX: ["gpt-5"], REASONING: ["o3"] },
classifier_type: "heuristic" as const,
semantic_keyword_matching: true,
embedding_model: "gpt-5-nano",
match_threshold: 0,
keyword_tier_rules: [{ keywords: ["foo"], tier: "SIMPLE" as const }],
escalation_keywords: [],
},
},
}));
vi.mock("@/lib/autorouter_presets", async (importOriginal) => {
const actual = await importOriginal<typeof import("@/lib/autorouter_presets")>();
const withSynthetic = [...actual.getAllPresets(), FALSY_PRESET];
return {
...actual,
getAllPresets: () => withSynthetic,
getPresetByKey: (key: string) => withSynthetic.find((preset) => preset.key === key),
};
});
// A real TeamDropdown fetches teams and renders an antd Select; the wiring under test is
// whether team_id is registered, validated and forwarded, so a plain control stands in.
vi.mock("../common_components/team_dropdown", () => ({
@ -213,6 +244,85 @@ describe("AddAutoRouterTab", () => {
expect(mockHandleAddAutoRouterSubmit).not.toHaveBeenCalled();
});
// A caller switch must reset the form and re-enter the loading gate until the NEW caller's models
// arrive, or the previous caller's verified list keeps a preset selectable and submittable for a
// caller who may lack those models. Caller A selects OpenAI (config filled); caller B's fetch is
// held open, so during that window the option must be disabled again (loading gate) AND the filled
// config must be gone, so B cannot submit A's preset. Dropping the reset re-enables the option and
// carries A's tiers into B's submit.
it("resets the form and re-enters the loading gate while the new caller's models are fetching", async () => {
const user = userEvent.setup();
let resolveB: (models: ModelGroup[]) => void = () => undefined;
mockFetchAvailableModels
.mockResolvedValueOnce(ALL_FAMILY_MODELS)
.mockReturnValueOnce(new Promise<ModelGroup[]>((resolve) => (resolveB = resolve)));
const { rerender } = renderWithProviders(
<AddAutoRouterTab handleOk={vi.fn()} accessToken="caller-a" userRole="Admin" />,
);
openTemplateDropdown();
await waitFor(() => expect(isOptionDisabled(optionByLabel("OpenAI Family")!)).toBe(false));
fireEvent.click(optionByLabel("OpenAI Family")!);
rerender(<AddAutoRouterTab handleOk={vi.fn()} accessToken="caller-b" userRole="Admin" />);
await waitFor(() => expect(mockFetchAvailableModels).toHaveBeenCalledTimes(2));
openTemplateDropdown();
await waitFor(() => expect(isOptionDisabled(optionByLabel("OpenAI Family")!)).toBe(true));
expect(optionByLabel("OpenAI Family")).toHaveTextContent(/Checking model availability/);
await user.type(screen.getByPlaceholderText(/smart_router/i), "caller-b-router");
await user.click(screen.getByRole("button", { name: /add auto router/i }));
expect(mockHandleAddAutoRouterSubmit).not.toHaveBeenCalled();
resolveB([]);
});
// A late-resolving fetch from the previous caller must not overwrite the current caller's list.
// Caller A's request is held open, caller B's resolves empty; when A finally resolves with the
// full family, the ignore guard drops it so the preset stays greyed out for B. Without the guard,
// A's response would land after B's and wrongly re-enable the preset.
it("ignores a stale in-flight model fetch that resolves after the token changed", async () => {
let resolveA: (models: ModelGroup[]) => void = () => undefined;
mockFetchAvailableModels
.mockReturnValueOnce(new Promise<ModelGroup[]>((resolve) => (resolveA = resolve)))
.mockResolvedValueOnce([]);
const { rerender } = renderWithProviders(
<AddAutoRouterTab handleOk={vi.fn()} accessToken="caller-a" userRole="Admin" />,
);
rerender(<AddAutoRouterTab handleOk={vi.fn()} accessToken="caller-b" userRole="Admin" />);
await waitFor(() => expect(mockFetchAvailableModels).toHaveBeenCalledTimes(2));
resolveA(ALL_FAMILY_MODELS);
openTemplateDropdown();
await waitFor(() => expect(optionByLabel("OpenAI Family")).toBeTruthy());
expect(isOptionDisabled(optionByLabel("OpenAI Family")!)).toBe(true);
});
// Prefill must preserve a preset's deliberately-falsy fields (a 0 match threshold, an empty
// escalation list). Using `||` instead of `??` would swap the 0 for the create-form default and
// re-enable escalation the preset meant to turn off, so this asserts the exact submitted values.
it("preserves a preset's zero match threshold and empty escalation list through submit", async () => {
const user = userEvent.setup();
mockFetchAvailableModels.mockResolvedValue(ALL_FAMILY_MODELS);
renderWithProviders(<Harness />);
openTemplateDropdown();
await waitFor(() => expect(isOptionDisabled(optionByLabel("Falsy Family")!)).toBe(false));
fireEvent.click(optionByLabel("Falsy Family")!);
await user.type(screen.getByPlaceholderText(/smart_router/i), "falsy-router");
await user.click(screen.getByRole("button", { name: /add auto router/i }));
await waitFor(() => expect(mockHandleAddAutoRouterSubmit).toHaveBeenCalled());
const payload = mockHandleAddAutoRouterSubmit.mock.calls.at(-1)?.[0];
expect(payload.complexity_router_config.match_threshold).toBe(0);
expect(payload.complexity_router_config.escalation_keywords).toEqual([]);
});
it("offers no team selector to a proxy admin, who may create an unscoped router", () => {
renderWithProviders(<Harness />);

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { Card, Form, Button, Tooltip, Typography, Select as AntdSelect, Modal } from "antd";
import { TextInput } from "@tremor/react";
import { modelAvailableCall } from "../networking";
@ -106,19 +106,44 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
fetchModelAccessGroups();
}, [accessToken]);
const resetToCustom = useCallback(() => {
setComplexityRouterConfig({
tiers: { SIMPLE: [], MEDIUM: [], COMPLEX: [], REASONING: [] },
classifier_type: "heuristic",
});
setCustomTechnicalKeywords([]);
setKeywordTierRules([]);
setSemanticMatchingEnabled(false);
setEmbeddingModel(undefined);
setMatchThreshold(DEFAULT_MATCH_THRESHOLD);
setEscalationKeywords(DEFAULT_ESCALATION_KEYWORDS);
}, []);
useEffect(() => {
let ignore = false;
const loadModels = async () => {
setModelsLoadState("loading");
setModelInfo([]);
setSelectedPreset(undefined);
resetToCustom();
try {
const uniqueModels = await fetchAvailableModels(accessToken);
if (ignore) return;
setModelInfo(uniqueModels);
setModelsLoadState("loaded");
} catch (error) {
console.error("Error fetching model info for auto router:", error);
if (ignore) return;
setModelsLoadState("error");
}
};
loadModels();
}, [accessToken]);
return () => {
ignore = true;
};
}, [accessToken, resetToCustom]);
const isAdmin = all_admin_roles.includes(userRole);
@ -128,7 +153,7 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
}));
const availableModelSet = new Set(modelInfo.map((m) => m.model_group));
const presets = getAllPresets();
const presets = React.useMemo(() => getAllPresets(), []);
// A preset's models can only be trusted against a successfully loaded list. Selection and the
// greyed-out state derive from this one function, so a preset that cannot be selected can never
@ -142,19 +167,6 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
return missing.length > 0 ? { kind: "missing_models", models: missing } : { kind: "available" };
};
const resetToCustom = () => {
setComplexityRouterConfig({
tiers: { SIMPLE: [], MEDIUM: [], COMPLEX: [], REASONING: [] },
classifier_type: "heuristic",
});
setCustomTechnicalKeywords([]);
setKeywordTierRules([]);
setSemanticMatchingEnabled(false);
setEmbeddingModel(undefined);
setMatchThreshold(DEFAULT_MATCH_THRESHOLD);
setEscalationKeywords(DEFAULT_ESCALATION_KEYWORDS);
};
const handlePresetChange = (presetKey: string | undefined) => {
if (!presetKey || presetKey === "custom") {
setSelectedPreset(presetKey);
@ -182,12 +194,12 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
};
setComplexityRouterConfig(presetComplexityRouterConfig);
setCustomTechnicalKeywords(config.custom_technical_keywords || []);
setKeywordTierRules(hydrateKeywordTierRules(config.keyword_tier_rules || []));
setSemanticMatchingEnabled(config.semantic_keyword_matching || false);
setCustomTechnicalKeywords(config.custom_technical_keywords ?? []);
setKeywordTierRules(hydrateKeywordTierRules(config.keyword_tier_rules ?? []));
setSemanticMatchingEnabled(config.semantic_keyword_matching ?? false);
setEmbeddingModel(config.embedding_model);
setMatchThreshold(config.match_threshold || DEFAULT_MATCH_THRESHOLD);
setEscalationKeywords(config.escalation_keywords || DEFAULT_ESCALATION_KEYWORDS);
setMatchThreshold(config.match_threshold ?? DEFAULT_MATCH_THRESHOLD);
setEscalationKeywords(config.escalation_keywords ?? DEFAULT_ESCALATION_KEYWORDS);
};
const submitRecommendedRouter = (name: string) => {