feat(ui): make automatic auto-router setup discoverable and show what it configured (#40146)

* fix(ui): expand Detailed Configuration after automatic auto-router setup

* feat(ui): promote automatic auto-router setup to a callout banner

* test(ui): read tier chips through testing-library queries to stay in lint budget

* style(ui): drop explanatory comments per repo convention

* test(ui): reject unexpected automatic tier models
This commit is contained in:
tin-berri 2026-09-07 13:55:27 -07:00 committed by GitHub
parent b618c7ad86
commit 7c1745cc71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 45 additions and 21 deletions

View file

@ -60,6 +60,20 @@ const optionByLabel = (label: string): HTMLElement | undefined =>
const isOptionDisabled = (option: HTMLElement): boolean => option.getAttribute("aria-disabled") === "true";
const tierChips = (tier: string): HTMLElement => {
const placeholder = `Select model(s) for ${tier.toLowerCase()} queries`;
const chips = screen
.getAllByRole("toolbar")
.find((candidate) => within(candidate).queryByLabelText(placeholder) !== null);
if (!chips) throw new Error(`No tier row found for "${tier}"`);
return chips;
};
const expectTierModel = (tier: string, model: string): void => {
const chips = within(tierChips(tier)).getAllByLabelText(/.+/, { selector: '[data-slot="combobox-chip"]' });
expect(chips.map((chip) => chip.getAttribute("aria-label"))).toEqual([model]);
};
const selectTemplate = async (label: string): Promise<void> => {
await userEvent.click(optionByLabel(label)!);
};
@ -188,11 +202,10 @@ describe("AddAutoRouterTab", () => {
const button = await screen.findByTestId("configure-automatically-button");
await userEvent.click(button);
expect(
screen.getByText(
/Simple: gpt-5.6-luna.*Medium: claude-sonnet-5.*Complex: claude-opus-5.*Reasoning: claude-opus-5/,
),
).toBeInTheDocument();
expectTierModel("Simple", "gpt-5.6-luna");
expectTierModel("Medium", "claude-sonnet-5");
expectTierModel("Complex", "claude-opus-5");
expectTierModel("Reasoning", "claude-opus-5");
expect(toast.success).not.toHaveBeenCalledWith(expect.stringContaining("Configured with"));
});
@ -209,9 +222,23 @@ describe("AddAutoRouterTab", () => {
const button = await screen.findByTestId("configure-automatically-button");
await userEvent.click(button);
expect(
screen.getByText(/Simple: gpt-5.6-luna.*Medium: claude-sonnet-5.*Complex: gpt-5.6-sol.*Reasoning: gpt-5.6-sol/),
).toBeInTheDocument();
expectTierModel("Simple", "gpt-5.6-luna");
expectTierModel("Medium", "claude-sonnet-5");
expectTierModel("Complex", "gpt-5.6-sol");
expectTierModel("Reasoning", "gpt-5.6-sol");
});
it("opens Detailed Configuration on the tiers automatic setup just filled in", async () => {
const simpleModel = "gpt-5.6-luna";
mockFetchAvailableModels.mockResolvedValue([...ALL_FAMILY_MODELS, { model_group: simpleModel, mode: "chat" }]);
renderWithProviders(<Harness />);
expect(screen.queryByText("Complexity Tier Configuration")).not.toBeInTheDocument();
await userEvent.click(await screen.findByTestId("configure-automatically-button"));
expect(screen.getByText("Complexity Tier Configuration")).toBeInTheDocument();
expectTierModel("Simple", simpleModel);
});
// Nothing is filled in, so there is nothing to submit. The button reports that itself instead of

View file

@ -207,10 +207,6 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
const [isSubmitting, setIsSubmitting] = useState(false);
const [selectedPreset, setSelectedPreset] = useState<string | undefined>(undefined);
// Closed by default: a caller opens it deliberately, either by clicking it or by choosing Custom
// (which expands it automatically, since there's nothing else to show them their config from). A
// preset re-collapses it after prefilling, offering the same "here's what got filled in, expand to
// change it" affordance. A caller can always toggle it manually at any point.
const [detailsExpanded, setDetailsExpanded] = useState<boolean>(false);
const [isRoutingTestVisible, setIsRoutingTestVisible] = useState<boolean>(false);
@ -335,7 +331,7 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
if (automaticRouterConfig === null) return;
setSelectedPreset(undefined);
applyPrefill({ ...buildEmptyPrefill(), complexityRouterConfig: automaticRouterConfig });
setDetailsExpanded(false);
setDetailsExpanded(true);
toast.success("Automatic setup created", { description: tierConfigSummary(automaticRouterConfig) });
};
@ -543,14 +539,15 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
</FormField>
{!automaticSetupLoading && automaticRouterConfig && (
<button
type="button"
className="mt-3 rounded-sm text-sm font-medium text-blue-600 hover:text-blue-700 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
data-testid="configure-automatically-button"
onClick={handleAutomaticSetup}
>
Configure automatically
</button>
<div className="mt-5 flex flex-wrap items-center justify-between gap-3 rounded-lg border border-border bg-muted px-4 py-3">
<div>
<p className="text-sm font-medium text-foreground">Not sure where to start?</p>
<p className="text-sm text-muted-foreground">Let us pick models for each complexity tier.</p>
</div>
<Button type="button" data-testid="configure-automatically-button" onClick={handleAutomaticSetup}>
Configure automatically
</Button>
</div>
)}
<div className="mt-5">