Fix other instances of issues with the litellm model list (#11773)

* Fix other instances of issues with the litellm model list

* address comment
This commit is contained in:
Tomás Barreiro
2026-06-24 06:20:32 +02:00
committed by GitHub
parent 8e5a3993a7
commit 6175896d65
4 changed files with 82 additions and 13 deletions
@@ -309,6 +309,47 @@ describe("resolveProviderConfig", () => {
expect(resolved?.knownModels?.["gpt-5.4"]).toBeUndefined();
});
it("returns an empty authoritative LiteLLM model list without auth", async () => {
const fetchMock = vi.fn();
vi.stubGlobal("fetch", fetchMock);
const resolved = await resolveProviderConfig(
"litellm",
{ failOnError: true, cacheTtlMs: 0 },
{
providerId: "litellm",
modelId: "",
baseUrl: "http://localhost:4000/v1/",
},
);
expect(fetchMock).not.toHaveBeenCalled();
expect(resolved?.knownModels).toEqual({});
expect(resolved?.knownModels?.["gpt-5.4"]).toBeUndefined();
});
it("does not fall back to bundled LiteLLM models when private model fetch fails non-strictly", async () => {
const fetchMock = vi.fn(
async () => new Response('{"error":"unauthorized"}', { status: 401 }),
);
vi.stubGlobal("fetch", fetchMock);
const resolved = await resolveProviderConfig(
"litellm",
{ failOnError: false, cacheTtlMs: 0 },
{
providerId: "litellm",
modelId: "",
apiKey: "litellm-key",
baseUrl: "http://localhost:4000",
},
);
expect(fetchMock).toHaveBeenCalled();
expect(resolved?.knownModels).toEqual({});
expect(resolved?.knownModels?.["gpt-5.4"]).toBeUndefined();
});
it("reports attempted path, auth header, status, and body for LiteLLM model fetch failures", async () => {
const fetchMock = vi.fn(
async () => new Response('{"error":"unauthorized"}', { status: 401 }),
@@ -149,6 +149,10 @@ async function mergeKnownModels(
publicModels: Record<string, ModelInfo> = {},
userKnownModels: Record<string, ModelInfo> = {},
): Promise<Record<string, ModelInfo>> {
if (providerId === "litellm") {
return Llms.sortModelsByReleaseDate(privateModels);
}
const generatedProviderModels = await loadGeneratedProviderModels();
const generatedKeys = Llms.resolveProviderModelCatalogKeys(providerId);
const generated = Object.assign(
@@ -171,16 +175,6 @@ async function mergeKnownModels(
...userKnownModels,
});
}
// LiteLLM model access is configured by the user's proxy. When the proxy
// returns a private model list, treat it as the authoritative allowlist so
// the picker does not show bundled OpenAI-compatible catalog entries that the
// proxy may not actually expose.
if (providerId === "litellm" && Object.keys(privateModels).length > 0) {
return Llms.sortModelsByReleaseDate({
...privateModels,
...userKnownModels,
});
}
if (providerId === "openai-codex") {
return Llms.sortModelsByReleaseDate({
...defaultKnownModels,
@@ -937,6 +931,12 @@ export async function resolveProviderConfig(
if (modelCatalog?.failOnError) {
throw error;
}
if (providerId === "litellm") {
return {
...defaults,
knownModels: {},
};
}
return defaults;
}
}
@@ -598,7 +598,7 @@ describe("addLocalProvider capabilities", () => {
expect(models[0].supportsReasoning).toBeFalsy();
});
it("merges LiteLLM private models into the provider model listing when auth is configured", async () => {
it("uses LiteLLM private models as the authoritative provider model listing when auth is configured", async () => {
manager.saveProviderSettings(
{
provider: "litellm",
@@ -632,8 +632,11 @@ describe("addLocalProvider capabilities", () => {
manager.getProviderConfig("litellm"),
);
expect(models.map((model) => model.id)).toContain("private-proxy-model");
expect(models.map((model) => model.id)).toContain("openai/gpt-4o-mini");
expect(models.map((model) => model.id).sort()).toEqual([
"openai/gpt-4o-mini",
"private-proxy-model",
]);
expect(models.map((model) => model.id)).not.toContain("gpt-5.4");
expect(
models.find((model) => model.id === "private-proxy-model"),
).toMatchObject({
@@ -641,6 +644,27 @@ describe("addLocalProvider capabilities", () => {
supportsReasoning: true,
});
});
it("uses an empty LiteLLM model list when no private model list is fetched", async () => {
manager.saveProviderSettings(
{
provider: "litellm",
baseUrl: "http://localhost:4010",
model: "gpt-4o",
},
{ setLastUsed: false },
);
const fetchMock = vi.fn();
vi.stubGlobal("fetch", fetchMock);
const { models } = await getLocalProviderModels(
"litellm",
manager.getProviderConfig("litellm"),
);
expect(fetchMock).not.toHaveBeenCalled();
expect(models).toEqual([]);
});
});
// ===========================================================================
@@ -136,6 +136,10 @@ async function resolveProviderModelMap(
config,
);
if (providerId === "litellm" && resolved?.knownModels) {
return resolved.knownModels;
}
return resolved?.knownModels
? {
...registeredModels,