mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-14 04:09:09 +00:00
fix(ui): friendly fallback group labels, page padding, short LiteAdmin action title
Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
This commit is contained in:
parent
cc4fc1b3a1
commit
0bd1fcd940
4 changed files with 55 additions and 20 deletions
|
|
@ -6,12 +6,10 @@ import Fallbacks from "@/components/Settings/RouterSettings/Fallbacks/Fallbacks"
|
|||
export default function FallbacksPage() {
|
||||
const { accessToken, userRole, userId } = useAuthorized();
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-4 px-8 py-6">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h1 className="text-2xl font-bold">Fallbacks</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Automatically retry a different model when the primary fails
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">Automatically retry a different model when the primary fails</p>
|
||||
</div>
|
||||
<Fallbacks accessToken={accessToken} userRole={userRole} userID={userId} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,11 @@ describe("FallbackSelectionForm", () => {
|
|||
it("should display tabs when groups exist", () => {
|
||||
const groups: FallbackGroup[] = [{ id: "1", primaryModel: null, fallbackModels: [] }];
|
||||
render(
|
||||
<FallbackSelectionForm groups={groups} onGroupsChange={mockOnGroupsChange} modelGroups={AVAILABLE_MODEL_GROUPS} />,
|
||||
<FallbackSelectionForm
|
||||
groups={groups}
|
||||
onGroupsChange={mockOnGroupsChange}
|
||||
modelGroups={AVAILABLE_MODEL_GROUPS}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("tab", { name: /group 1/i })).toBeInTheDocument();
|
||||
});
|
||||
|
|
@ -61,16 +65,36 @@ describe("FallbackSelectionForm", () => {
|
|||
it("should display primary model as tab label when set", () => {
|
||||
const groups: FallbackGroup[] = [{ id: "1", primaryModel: "gpt-4", fallbackModels: [] }];
|
||||
render(
|
||||
<FallbackSelectionForm groups={groups} onGroupsChange={mockOnGroupsChange} modelGroups={AVAILABLE_MODEL_GROUPS} />,
|
||||
<FallbackSelectionForm
|
||||
groups={groups}
|
||||
onGroupsChange={mockOnGroupsChange}
|
||||
modelGroups={AVAILABLE_MODEL_GROUPS}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("tab", { name: "gpt-4" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should display friendly label for provider wildcard primary", () => {
|
||||
const groups: FallbackGroup[] = [{ id: "1", primaryModel: "openai/*", fallbackModels: [] }];
|
||||
render(
|
||||
<FallbackSelectionForm
|
||||
groups={groups}
|
||||
onGroupsChange={mockOnGroupsChange}
|
||||
modelGroups={AVAILABLE_MODEL_GROUPS}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("tab", { name: "All OpenAI Models" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should call onGroupsChange when add tab button is clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
const groups: FallbackGroup[] = [{ id: "1", primaryModel: null, fallbackModels: [] }];
|
||||
render(
|
||||
<FallbackSelectionForm groups={groups} onGroupsChange={mockOnGroupsChange} modelGroups={AVAILABLE_MODEL_GROUPS} />,
|
||||
<FallbackSelectionForm
|
||||
groups={groups}
|
||||
onGroupsChange={mockOnGroupsChange}
|
||||
modelGroups={AVAILABLE_MODEL_GROUPS}
|
||||
/>,
|
||||
);
|
||||
|
||||
const addTabButton = screen.getByRole("button", { name: /add fallback group/i });
|
||||
|
|
@ -125,7 +149,11 @@ describe("FallbackSelectionForm", () => {
|
|||
{ id: "2", primaryModel: "gpt-3.5-turbo", fallbackModels: [] },
|
||||
];
|
||||
render(
|
||||
<FallbackSelectionForm groups={groups} onGroupsChange={mockOnGroupsChange} modelGroups={AVAILABLE_MODEL_GROUPS} />,
|
||||
<FallbackSelectionForm
|
||||
groups={groups}
|
||||
onGroupsChange={mockOnGroupsChange}
|
||||
modelGroups={AVAILABLE_MODEL_GROUPS}
|
||||
/>,
|
||||
);
|
||||
|
||||
const removeButtons = screen.getAllByRole("button", { name: /^remove /i });
|
||||
|
|
@ -142,7 +170,11 @@ describe("FallbackSelectionForm", () => {
|
|||
it("should render FallbackGroupConfig for each group", () => {
|
||||
const groups: FallbackGroup[] = [{ id: "1", primaryModel: null, fallbackModels: [] }];
|
||||
render(
|
||||
<FallbackSelectionForm groups={groups} onGroupsChange={mockOnGroupsChange} modelGroups={AVAILABLE_MODEL_GROUPS} />,
|
||||
<FallbackSelectionForm
|
||||
groups={groups}
|
||||
onGroupsChange={mockOnGroupsChange}
|
||||
modelGroups={AVAILABLE_MODEL_GROUPS}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("combobox", { name: /primary model/i })).toHaveValue("");
|
||||
expect(screen.getByText("Primary Model")).toBeInTheDocument();
|
||||
|
|
@ -151,7 +183,11 @@ describe("FallbackSelectionForm", () => {
|
|||
it("should display group with primary and fallback models in FallbackGroupConfig", () => {
|
||||
const groups: FallbackGroup[] = [{ id: "1", primaryModel: "gpt-4", fallbackModels: ["gpt-3.5-turbo"] }];
|
||||
render(
|
||||
<FallbackSelectionForm groups={groups} onGroupsChange={mockOnGroupsChange} modelGroups={AVAILABLE_MODEL_GROUPS} />,
|
||||
<FallbackSelectionForm
|
||||
groups={groups}
|
||||
onGroupsChange={mockOnGroupsChange}
|
||||
modelGroups={AVAILABLE_MODEL_GROUPS}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("tab", { name: "gpt-4" })).toBeInTheDocument();
|
||||
expect(screen.getAllByText("gpt-4").length).toBeGreaterThan(0);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|||
import { Plus, X } from "lucide-react";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "@/lib/toast";
|
||||
import { fallbackChainOptions, primaryModelOptions } from "./fallbackOptions";
|
||||
import { fallbackChainOptions, fallbackPrimaryLabel, primaryModelOptions } from "./fallbackOptions";
|
||||
import { FallbackGroup, FallbackGroupConfig } from "./FallbackGroupConfig";
|
||||
|
||||
interface FallbackSelectionFormProps {
|
||||
|
|
@ -81,7 +81,7 @@ export function FallbackSelectionForm({
|
|||
};
|
||||
|
||||
const groupLabel = (group: FallbackGroup, index: number) =>
|
||||
group.primaryModel ? group.primaryModel : `Group ${index + 1}`;
|
||||
group.primaryModel ? fallbackPrimaryLabel(group.primaryModel) : `Group ${index + 1}`;
|
||||
|
||||
if (groups.length === 0) {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -109,7 +109,11 @@ const fallbackSetFields = {
|
|||
model: text.describe(
|
||||
"The primary model group, or a provider wildcard like openai/* meaning all models from that provider.",
|
||||
),
|
||||
fallbacks: z.array(fallbackTarget).min(1).max(10),
|
||||
fallbacks: z
|
||||
.array(fallbackTarget)
|
||||
.min(1)
|
||||
.max(10)
|
||||
.describe("Concrete model groups to try in order. Never a wildcard."),
|
||||
};
|
||||
const fallbackDeleteFields = { model: text };
|
||||
|
||||
|
|
@ -359,15 +363,12 @@ export function createLiteAdminOperations(context: OperationContext) {
|
|||
query: { ...a, start_date: `${a.start_date} 00:00:00`, end_date: `${a.end_date} 23:59:59` },
|
||||
}),
|
||||
),
|
||||
operation("read", "fallback")(
|
||||
"fallbacks_list",
|
||||
"List configured router fallbacks",
|
||||
object({}),
|
||||
async () => ({ fallbacks: fallbackEntries(await readRouterSettings()) }),
|
||||
),
|
||||
operation("read", "fallback")("fallbacks_list", "List configured router fallbacks", object({}), async () => ({
|
||||
fallbacks: fallbackEntries(await readRouterSettings()),
|
||||
})),
|
||||
operation("write", "fallback")(
|
||||
"fallback_set",
|
||||
"Set the fallback chain for a primary model. The model may be a provider wildcard like openai/* meaning all models from that provider; wildcards are allowed as model but never inside fallbacks",
|
||||
"Set the fallback chain for a model",
|
||||
object(fallbackSetFields),
|
||||
async (a) => {
|
||||
const settings = await readRouterSettings();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue