mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-08 22:21:35 +00:00
fix(ui): clearing the context-window buffer removes it from the payload
Both review bots converged on the same defect: an emptied buffer field early-returned in commitBuffer, the draft was discarded on blur, and the stale number reappeared and stayed in the saved config, contradicting the copy that an empty field tracks the backend default. An empty commit now removes the key, which the managed-keys projection propagates as a real deletion on edit. Also trims the narrative comments the review flagged as restating behavior
This commit is contained in:
parent
3793366a43
commit
d7da446183
4 changed files with 29 additions and 9 deletions
|
|
@ -8,13 +8,16 @@ const ContextWindowEscalationConfig: React.FC<{
|
|||
onChange: (value: ComplexityRouterConfigValue) => void;
|
||||
}> = ({ value, onChange }) => {
|
||||
const enabled = value.enable_context_window_escalation ?? true;
|
||||
// A number input renders Number("0.") as "0", so a decimal cannot be typed without a local draft.
|
||||
const [bufferDraft, setBufferDraft] = React.useState<string | null>(null);
|
||||
// min/max are inert on a text input, and a plain number input renders Number("0.") as "0" so a
|
||||
// decimal cannot be typed. Hence the local draft plus an explicit clamp on commit.
|
||||
const commitBuffer = (raw: string) => {
|
||||
setBufferDraft(null);
|
||||
if (raw.trim() === "") {
|
||||
onChange({ ...value, context_window_escalation_buffer: undefined });
|
||||
return;
|
||||
}
|
||||
const parsed = Number(raw);
|
||||
if (raw.trim() === "" || !Number.isFinite(parsed)) return;
|
||||
if (!Number.isFinite(parsed)) return;
|
||||
onChange({ ...value, context_window_escalation_buffer: Math.min(1, Math.max(0.01, parsed)) });
|
||||
};
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -394,8 +394,6 @@ describe("AddAutoRouterTab", () => {
|
|||
});
|
||||
});
|
||||
|
||||
// A plain number input renders Number("1.5") fine but the clamp is ours: values above 1 must commit as 1,
|
||||
// and an untouched buffer must stay out of the payload so the router tracks the backend default.
|
||||
it("clamps the context-window buffer to 1 and keeps an untouched buffer out of the payload", async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(getMissingTiersError).mockReturnValue(null);
|
||||
|
|
@ -417,6 +415,29 @@ describe("AddAutoRouterTab", () => {
|
|||
expect(config).not.toHaveProperty("enable_context_window_escalation");
|
||||
});
|
||||
|
||||
it("clearing the buffer removes it from the payload so the router tracks the backend default", async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(getMissingTiersError).mockReturnValue(null);
|
||||
|
||||
renderWithProviders(<Harness />);
|
||||
|
||||
await user.type(screen.getByPlaceholderText(/smart_router/i), "ctx-clear-router");
|
||||
expandDetailedConfiguration();
|
||||
await user.click(screen.getByText("Advanced: Context Window Escalation"));
|
||||
const buffer = await screen.findByLabelText("Window fit buffer");
|
||||
fireEvent.change(buffer, { target: { value: "0.8" } });
|
||||
fireEvent.blur(buffer, { target: { value: "0.8" } });
|
||||
fireEvent.change(buffer, { target: { value: "" } });
|
||||
fireEvent.blur(buffer, { target: { value: "" } });
|
||||
|
||||
await user.click(screen.getByRole("button", { name: /add auto router/i }));
|
||||
|
||||
await waitFor(() => expect(handleAddAutoRouterSubmit).toHaveBeenCalled());
|
||||
expect(vi.mocked(handleAddAutoRouterSubmit).mock.calls.at(-1)?.[0].complexity_router_config).not.toHaveProperty(
|
||||
"context_window_escalation_buffer",
|
||||
);
|
||||
});
|
||||
|
||||
// The scalar floor is the one scorer knob with no group dict behind it, so its wiring into the create
|
||||
// payload is only proven end to end. 0 is the case a truthy check would silently drop.
|
||||
it("carries a reasoning override floor of 0 through to the create payload", async () => {
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ describe("buildComplexityRouterConfig", () => {
|
|||
expect(config).toEqual(expected);
|
||||
});
|
||||
|
||||
// False is the value a truthy guard would silently drop, and it is the whole point of the toggle:
|
||||
// an untouched form tracks the backend default (enabled), an explicit false is a real opt-out.
|
||||
it("carries an explicit context-window escalation opt-out and buffer, false included", () => {
|
||||
const config = buildComplexityRouterConfig({
|
||||
...baseParams,
|
||||
|
|
|
|||
|
|
@ -573,8 +573,6 @@ describe("autorouter_presets", () => {
|
|||
expect(prefill.escalationKeywords).toEqual([]);
|
||||
});
|
||||
|
||||
// The prefill mapping is a hand-written field list, so a new config key is silently dropped
|
||||
// unless mapped; false is the value a `||` default would erase (the #38453 class).
|
||||
it("carries a preset's context-window escalation opt-out and buffer through the prefill", () => {
|
||||
const prefill = buildPresetPrefill(
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue