mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
Revert "Expose new model provider map endpoint and use in add model workflow"
This reverts commit 8a4fefc565.
This commit is contained in:
parent
8a4fefc565
commit
b50790aaad
5 changed files with 8 additions and 285 deletions
|
|
@ -116,54 +116,3 @@ async def get_provider_fields() -> List[ProviderCreateInfo]:
|
|||
"""
|
||||
|
||||
return get_provider_create_metadata()
|
||||
|
||||
|
||||
@router.get(
|
||||
"/public/model_provider_map",
|
||||
tags=["public", "model management"],
|
||||
)
|
||||
async def get_model_provider_map():
|
||||
"""
|
||||
Return a mapping of model names to their litellm_provider and mode.
|
||||
This is a public endpoint that provides the same structure as /get/litellm_model_cost_map
|
||||
but without cost information, making it accessible to non-admin users.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary mapping model names to their provider information:
|
||||
{
|
||||
"model_name": {
|
||||
"litellm_provider": "provider_name",
|
||||
"mode": "chat" | "completion" | "embedding" | "image_generation" | "audio_transcription" | ...
|
||||
},
|
||||
...
|
||||
}
|
||||
"""
|
||||
import litellm
|
||||
|
||||
try:
|
||||
_model_cost_map = litellm.model_cost
|
||||
if not _model_cost_map:
|
||||
return {}
|
||||
|
||||
# Extract the litellm_provider and mode fields from each model entry
|
||||
model_provider_map = {}
|
||||
for model_name, model_info in _model_cost_map.items():
|
||||
if isinstance(model_info, dict) and "litellm_provider" in model_info:
|
||||
litellm_provider = model_info["litellm_provider"]
|
||||
# Only include if litellm_provider is not None/empty
|
||||
if litellm_provider:
|
||||
model_entry = {
|
||||
"litellm_provider": litellm_provider
|
||||
}
|
||||
# Include mode if it exists
|
||||
if "mode" in model_info and model_info["mode"]:
|
||||
model_entry["mode"] = model_info["mode"]
|
||||
|
||||
model_provider_map[model_name] = model_entry
|
||||
|
||||
return model_provider_map
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Internal Server Error ({str(e)})",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -64,47 +64,3 @@ def test_get_provider_fields_returns_metadata():
|
|||
}
|
||||
assert {"api_base", "api_key"}.issubset(runway_credential_keys)
|
||||
|
||||
|
||||
def test_get_model_provider_map_returns_correct_structure():
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/public/model_provider_map")
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert isinstance(payload, dict)
|
||||
|
||||
# Verify structure: each entry should have litellm_provider, optionally mode
|
||||
for model_name, model_info in payload.items():
|
||||
assert isinstance(model_name, str)
|
||||
assert isinstance(model_info, dict)
|
||||
assert "litellm_provider" in model_info
|
||||
assert isinstance(model_info["litellm_provider"], str)
|
||||
assert len(model_info["litellm_provider"]) > 0
|
||||
|
||||
# If mode exists, it should be a valid string
|
||||
if "mode" in model_info:
|
||||
assert isinstance(model_info["mode"], str)
|
||||
assert len(model_info["mode"]) > 0
|
||||
|
||||
# Verify some common models exist (if model_cost is populated)
|
||||
if len(payload) > 0:
|
||||
# Check for at least one OpenAI model
|
||||
openai_models = [
|
||||
model for model, info in payload.items()
|
||||
if info.get("litellm_provider") == "openai"
|
||||
]
|
||||
# If OpenAI models exist, verify structure
|
||||
if openai_models:
|
||||
sample_model = openai_models[0]
|
||||
assert "litellm_provider" in payload[sample_model]
|
||||
assert payload[sample_model]["litellm_provider"] == "openai"
|
||||
# Most OpenAI models should have mode="chat"
|
||||
if "mode" in payload[sample_model]:
|
||||
assert payload[sample_model]["mode"] in [
|
||||
"chat", "completion", "embedding",
|
||||
"image_generation", "audio_transcription"
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,155 +0,0 @@
|
|||
import { render, waitFor, screen } from "@testing-library/react";
|
||||
import { describe, it, expect, vi, beforeEach, beforeAll } from "vitest";
|
||||
import ModelsAndEndpointsView from "./ModelsAndEndpointsView";
|
||||
import * as useAuthorizedModule from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import * as useTeamsModule from "@/app/(dashboard)/hooks/useTeams";
|
||||
|
||||
global.ResizeObserver = vi.fn().mockImplementation(() => ({
|
||||
observe: vi.fn(),
|
||||
unobserve: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
}));
|
||||
|
||||
const mockUseAuthorized = {
|
||||
token: "mock-token",
|
||||
accessToken: "mock-access-token",
|
||||
userId: "user-123",
|
||||
userEmail: "test@example.com",
|
||||
userRole: "Admin",
|
||||
premiumUser: true,
|
||||
disabledPersonalKeyCreation: false,
|
||||
showSSOBanner: false,
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
vi.spyOn(useAuthorizedModule, "default").mockReturnValue(mockUseAuthorized);
|
||||
vi.spyOn(useTeamsModule, "default").mockReturnValue({
|
||||
teams: [],
|
||||
setTeams: vi.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
vi.mock("@/components/networking", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("@/components/networking")>();
|
||||
return {
|
||||
...actual,
|
||||
modelInfoCall: vi.fn().mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
model_name: "gpt-4",
|
||||
litellm_params: {
|
||||
model: "gpt-4",
|
||||
custom_llm_provider: "openai",
|
||||
},
|
||||
model_info: {
|
||||
id: "model-1",
|
||||
access_groups: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
modelProviderMap: vi.fn().mockResolvedValue({
|
||||
"gpt-4": {
|
||||
litellm_provider: "openai",
|
||||
},
|
||||
}),
|
||||
modelSettingsCall: vi.fn().mockResolvedValue([]),
|
||||
credentialListCall: vi.fn().mockResolvedValue({
|
||||
credentials: [],
|
||||
}),
|
||||
modelMetricsCall: vi.fn().mockResolvedValue({
|
||||
data: [],
|
||||
all_api_bases: [],
|
||||
}),
|
||||
streamingModelMetricsCall: vi.fn().mockResolvedValue({
|
||||
data: [],
|
||||
all_api_bases: [],
|
||||
}),
|
||||
modelExceptionsCall: vi.fn().mockResolvedValue({
|
||||
data: [],
|
||||
exception_types: [],
|
||||
}),
|
||||
modelMetricsSlowResponsesCall: vi.fn().mockResolvedValue([]),
|
||||
getCallbacksCall: vi.fn().mockResolvedValue({
|
||||
router_settings: {
|
||||
model_group_retry_policy: {},
|
||||
retry_policy: {},
|
||||
num_retries: 0,
|
||||
model_group_alias: {},
|
||||
},
|
||||
}),
|
||||
setCallbacksCall: vi.fn().mockResolvedValue({}),
|
||||
adminGlobalActivityExceptions: vi.fn().mockResolvedValue({
|
||||
sum_num_rate_limit_exceptions: 0,
|
||||
daily_data: [],
|
||||
}),
|
||||
adminGlobalActivityExceptionsPerDeployment: vi.fn().mockResolvedValue([]),
|
||||
allEndUsersCall: vi.fn().mockResolvedValue([]),
|
||||
modelAvailableCall: vi.fn().mockResolvedValue({
|
||||
data: [],
|
||||
}),
|
||||
getPassThroughEndpointsCall: vi.fn().mockResolvedValue({
|
||||
data: [],
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
describe("ModelsAndEndpointsView", () => {
|
||||
const defaultProps = {
|
||||
accessToken: "test-access-token",
|
||||
token: "test-token",
|
||||
userRole: "Admin",
|
||||
userID: "test-user-id",
|
||||
modelData: {
|
||||
data: [
|
||||
{
|
||||
model_name: "gpt-4",
|
||||
litellm_params: {
|
||||
model: "gpt-4",
|
||||
custom_llm_provider: "openai",
|
||||
},
|
||||
model_info: {
|
||||
id: "model-1",
|
||||
access_groups: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
keys: [],
|
||||
setModelData: vi.fn(),
|
||||
premiumUser: true,
|
||||
teams: [],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("should render the component successfully", async () => {
|
||||
const { container } = render(<ModelsAndEndpointsView {...defaultProps} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(screen.getByText("Model Management")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render tabs", async () => {
|
||||
render(<ModelsAndEndpointsView {...defaultProps} />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Model Management")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const allModelsTabs = screen.getAllByRole("tab", { name: /All Models/i });
|
||||
expect(allModelsTabs.length).toBeGreaterThan(0);
|
||||
|
||||
const addModelTabs = screen.getAllByRole("tab", { name: /Add Model/i });
|
||||
expect(addModelTabs.length).toBeGreaterThan(0);
|
||||
|
||||
expect(screen.getByRole("tab", { name: /LLM Credentials/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole("tab", { name: /Pass-Through Endpoints/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole("tab", { name: /Health Status/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole("tab", { name: /Model Analytics/i })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
@ -10,7 +10,7 @@ import { TabPanel, TabPanels, TabGroup, TabList, Tab, Icon } from "@tremor/react
|
|||
import { DateRangePickerValue } from "@tremor/react";
|
||||
import {
|
||||
modelInfoCall,
|
||||
modelProviderMap,
|
||||
modelCostMap,
|
||||
modelMetricsCall,
|
||||
streamingModelMetricsCall,
|
||||
modelExceptionsCall,
|
||||
|
|
@ -418,17 +418,13 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
|||
fetchData();
|
||||
}
|
||||
|
||||
const fetchModelProviderMap = async () => {
|
||||
try {
|
||||
const data = await modelProviderMap();
|
||||
console.log(`received model provider map data: ${Object.keys(data).length} models`);
|
||||
setModelMap(data);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch model provider map:", error);
|
||||
}
|
||||
const fetchModelMap = async () => {
|
||||
const data = await modelCostMap(accessToken);
|
||||
console.log(`received model cost map data: ${Object.keys(data)}`);
|
||||
setModelMap(data);
|
||||
};
|
||||
if (modelMap == null) {
|
||||
fetchModelProviderMap();
|
||||
fetchModelMap();
|
||||
}
|
||||
|
||||
handleRefreshClick();
|
||||
|
|
|
|||
|
|
@ -306,31 +306,6 @@ export const getOpenAPISchema = async () => {
|
|||
return jsonData;
|
||||
};
|
||||
|
||||
export const modelProviderMap = async () => {
|
||||
try {
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/public/model_provider_map` : `/public/model_provider_map`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error("Failed to fetch model provider map:", response.status, errorText);
|
||||
throw new Error("Failed to load model provider mapping");
|
||||
}
|
||||
|
||||
const jsonData = await response.json();
|
||||
console.log(`received model provider map data: ${Object.keys(jsonData).length} models`);
|
||||
return jsonData;
|
||||
} catch (error) {
|
||||
console.error("Failed to get model provider map:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const modelCostMap = async (accessToken: string) => {
|
||||
try {
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/get/litellm_model_cost_map` : `/get/litellm_model_cost_map`;
|
||||
|
|
@ -6702,6 +6677,7 @@ export const getGuardrailProviderSpecificParams = async (accessToken: string) =>
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
export const getAgentsList = async (accessToken: string) => {
|
||||
try {
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/v1/agents` : `/v1/agents`;
|
||||
|
|
@ -6819,6 +6795,7 @@ export const patchAgentCall = async (
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
export const updateGuardrailCall = async (
|
||||
accessToken: string,
|
||||
guardrailId: string,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue