fix(ui): include endpoint-qualified models in Decisions Playground (#48504)

This commit is contained in:
tin-berri 2026-10-26 20:58:27 -04:00 • committed by GitHub
parent 715e9bb08d
commit 11779b260e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 30 additions and 5 deletions

View file

@ -207,18 +207,37 @@ describe("fetchDecisionModels", () => {
vi.unstubAllGlobals();
});
it("lists the key's decision models from the proxy that answers the request, sorted by name", async () => {
it("lists the key's models with decision modes or endpoints from the request proxy, sorted by name", async () => {
mockFetch.mockResolvedValueOnce(
modelGroupInfo([
{ model_group: "pplx-decider", mode: "evaluation" },
{ model_group: "gpt-5.5", mode: "chat" },
{ model_group: "jev-latest", mode: "evaluation" },
{ model_group: "unknown-mode", mode: null },
{ model_group: "native-decision", mode: "decisions" },
{
model_group: "chat-decisions",
mode: "chat",
supported_endpoints: ["/v1/chat/completions", "/v1/decisions"],
},
{ model_group: "chat-systemone", mode: "chat", supported_endpoints: ["/v1/systemone"] },
{ model_group: "custom-decision", mode: "custom", supported_endpoints: ["/v1/decisions"] },
{ model_group: "endpoint-only", supported_endpoints: ["/v1/decisions"] },
{ model_group: "chat-only", mode: "chat", supported_endpoints: ["/v1/chat/completions"] },
{ model_group: "no-endpoints", mode: "chat", supported_endpoints: [] },
{ model_group: "null-endpoints", mode: "chat", supported_endpoints: null },
{ model_group: "missing-mode" },
{ model_group: "custom-mode", mode: "custom" },
]),
);
await expect(fetchDecisionModels("virtual-key", "https://custom.example.com/")).resolves.toEqual([
"chat-decisions",
"chat-systemone",
"custom-decision",
"endpoint-only",
"jev-latest",
"native-decision",
"pplx-decider",
]);
expect(mockFetch).toHaveBeenCalledWith(

View file

@ -2,7 +2,7 @@ import { z } from "zod";
import { getGatewayBaseUrl, getGlobalLitellmHeaderName, getProxyBaseUrl } from "@/components/networking";
import { withRequiredHeaders } from "@/components/llm_calls/request_headers";
import { createApiClient } from "@/lib/http/client";
import { isDecisionMode } from "@/lib/decisionModels";
import { isDecisionEntry } from "@/lib/decisionModels";
import {
systemOneResponseSchema,
type PlaygroundRequest,
@ -26,7 +26,13 @@ export type PlaygroundDecisionRequest =
| { endpoint: "/v1/decisions"; payload: OpenAIDecisionsRequest };
const modelGroupInfoSchema = z.object({
data: z.array(z.object({ model_group: z.string(), mode: z.string().nullish() })),
data: z.array(
z.object({
model_group: z.string(),
mode: z.string().nullish(),
supported_endpoints: z.array(z.string()).nullish(),
}),
),
});
function proxyClient(customBaseUrl?: string, getDefaultBaseUrl: () => string = getProxyBaseUrl) {
@ -56,7 +62,7 @@ export async function fetchDecisionModels(
});
return modelGroupInfoSchema
.parse(body)
.data.filter((group) => isDecisionMode(group.mode))
.data.filter(isDecisionEntry)
.map((group) => group.model_group)
.sort((a, b) => a.localeCompare(b));
}

View file

@ -38,7 +38,7 @@ export const displayMode = (mode: string | null | undefined): string | undefined
export const expandModeFilterValues = (modes: readonly string[]): readonly string[] =>
modes.flatMap((mode) => (mode === DECISIONS_MODE ? DECISION_MODE_VALUES : [mode]));
const isDecisionEntry = (entry: CostMapEntry): boolean =>
export const isDecisionEntry = (entry: Pick<CostMapEntry, "mode" | "supported_endpoints">): boolean =>
isDecisionMode(entry.mode) || (entry.supported_endpoints ?? []).some((endpoint) => DECISION_ENDPOINTS.has(endpoint));
const parsedEntries = (costMap: unknown): ReadonlyArray<readonly [string, CostMapEntry]> => {