Revert "Expose new model provider map endpoint and use in add model workflow"

This reverts commit 8a4fefc565.
This commit is contained in:
yuneng-jiang 2025-11-20 20:40:08 -08:00
parent 8a4fefc565
commit b50790aaad
5 changed files with 8 additions and 285 deletions

View file

@ -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)})",
)

View file

@ -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"
]

View file

@ -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();
});
});

View file

@ -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();

View file

@ -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,