fix(ui): drop the decision models sublabel from the Add Model provider dropdown (#45755)

Co-authored-by: kerry <kerry@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
devin-ai-integration[bot] 2026-10-10 17:39:54 +00:00 • committed by GitHub
parent f8d21a0415
commit 38d0333fcc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 4 additions and 49 deletions

View file

@ -563,14 +563,6 @@ describe("AddModelPanel decision models", () => {
const decisionNotice = () => screen.queryByRole("note", { name: "Decision model notice" });
it("finds a provider by the name of one of its decision models", async () => {
const { user } = await setup();
await user.type(screen.getByRole("combobox", { name: /provider/i }), "jev");
expect(await screen.findByRole("option", { name: /TypeSafe/ })).toBeInTheDocument();
expect(screen.queryByRole("option", { name: /Anthropic/ })).not.toBeInTheDocument();
});
it("points a decision-only provider at the decision routes, the docs, and the playground", async () => {
const { user } = await setup();
await user.type(screen.getByRole("combobox", { name: /provider/i }), "TypeSafe");

View file

@ -39,7 +39,7 @@ import ProviderSpecificFields from "./provider_specific_fields";
import { authTypesFor } from "./provider_auth_types";
import { TEST_MODES } from "./add_model_modes";
import DecisionModelNote from "./DecisionModelNote";
import { decisionModelsSublabel, type DecisionCatalog } from "@/lib/decisionModels";
import { type DecisionCatalog } from "@/lib/decisionModels";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
import { credentialsKeys } from "@/app/(dashboard)/hooks/credentials/useCredentials";
import { extractProxyErrorMessage } from "@/lib/http/client";
@ -173,10 +173,9 @@ const AddModelForm: React.FC<AddModelFormProps> = ({
sortedProviderMetadata.map((providerInfo) => ({
label: providerInfo.provider_display_name,
value: providerInfo.provider,
sublabel: decisionModelsSublabel(decisionCatalog, providerInfo.litellm_provider),
icon: <ProviderLogo provider={providerInfo.provider} className="w-5 h-5" />,
})),
[sortedProviderMetadata, decisionCatalog],
[sortedProviderMetadata],
);
const pickedLitellmProvider = sortedProviderMetadata.find(

View file

@ -1,11 +1,5 @@
import { describe, expect, it } from "vitest";
import {
EMPTY_DECISION_CATALOG,
buildDecisionCatalog,
decisionModelsSublabel,
isDecisionMode,
isDecisionSelection,
} from "./decisionModels";
import { EMPTY_DECISION_CATALOG, buildDecisionCatalog, isDecisionMode, isDecisionSelection } from "./decisionModels";
const COST_MAP = {
"typesafe/jev-latest": { litellm_provider: "typesafe", mode: "evaluation" },
@ -46,12 +40,6 @@ describe("buildDecisionCatalog", () => {
);
});
it("strips the provider prefix from the names shown per provider", () => {
expect(catalog.providers.get("typesafe")?.names).toEqual(["jev-latest", "jev-preview"]);
expect(catalog.providers.get("perplexity")?.names).toEqual(["pplx-decider-v1-27b"]);
expect(catalog.providers.get("openai")?.names).toEqual(["gpt-6-luna"]);
});
it("marks a provider decision-only when every one of its models is a decision model", () => {
expect(catalog.providers.get("typesafe")?.decisionOnly).toBe(true);
expect(catalog.providers.get("somevendor")?.decisionOnly).toBe(true);
@ -70,18 +58,6 @@ describe("buildDecisionCatalog", () => {
});
});
describe("decisionModelsSublabel", () => {
const catalog = buildDecisionCatalog(COST_MAP);
it("lists the provider's decision models", () => {
expect(decisionModelsSublabel(catalog, "typesafe")).toBe("Decision models: jev-latest, jev-preview");
});
it("is undefined for a provider with no decision models", () => {
expect(decisionModelsSublabel(catalog, "anthropic")).toBeUndefined();
});
});
describe("isDecisionSelection", () => {
const catalog = buildDecisionCatalog(COST_MAP);

View file

@ -15,7 +15,6 @@ const costMapEntrySchema = z.object({
type CostMapEntry = z.infer<typeof costMapEntrySchema>;
interface ProviderDecisionModels {
readonly names: readonly string[];
readonly decisionOnly: boolean;
}
@ -31,9 +30,6 @@ export const isDecisionMode = (mode: string | null | undefined): boolean => mode
const isDecisionEntry = (entry: CostMapEntry): boolean =>
isDecisionMode(entry.mode) || (entry.supported_endpoints ?? []).some((endpoint) => DECISION_ENDPOINTS.has(endpoint));
const withoutProviderPrefix = (key: string, provider: string): string =>
key.startsWith(`${provider}/`) ? key.slice(provider.length + 1) : key;
const parsedEntries = (costMap: unknown): ReadonlyArray<readonly [string, CostMapEntry]> => {
const record = z.record(z.string(), z.unknown()).safeParse(costMap);
if (!record.success) {
@ -52,20 +48,12 @@ export function buildDecisionCatalog(costMap: unknown): DecisionCatalog {
const providers = new Map(
[...decisionProviders].map((provider) => {
const providerEntries = entries.filter(([, entry]) => entry.litellm_provider === provider);
const names = decisionEntries
.filter(([, entry]) => entry.litellm_provider === provider)
.map(([key]) => withoutProviderPrefix(key, provider));
return [provider, { names, decisionOnly: providerEntries.every(([, entry]) => isDecisionEntry(entry)) }] as const;
return [provider, { decisionOnly: providerEntries.every(([, entry]) => isDecisionEntry(entry)) }] as const;
}),
);
return { models: new Set(decisionEntries.map(([key]) => key)), providers };
}
export const decisionModelsSublabel = (catalog: DecisionCatalog, litellmProvider: string): string | undefined => {
const names = catalog.providers.get(litellmProvider)?.names ?? [];
return names.length > 0 ? `Decision models: ${names.join(", ")}` : undefined;
};
export const isDecisionSelection = (
catalog: DecisionCatalog,
litellmProvider: string | undefined,