Change Public Model Hub to use proxyBaseUrl (#16892)

This commit is contained in:
yuneng-jiang 2025-11-21 15:59:03 -08:00 • committed by GitHub
parent 1c65800f4a
commit b6b8f46b36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 140 additions and 60 deletions

View file

@ -0,0 +1,68 @@
import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
import { render } from "@testing-library/react";
import PublicModelHub from "./public_model_hub";
import { FeatureFlagsProvider } from "@/hooks/useFeatureFlags";
vi.mock("next/navigation", () => ({
useRouter: vi.fn(() => ({
replace: vi.fn(),
push: vi.fn(),
refresh: vi.fn(),
})),
}));
vi.mock("./networking", async (importOriginal) => {
const actual = await importOriginal<typeof import("./networking")>();
return {
...actual,
modelHubPublicModelsCall: vi.fn().mockResolvedValue([]),
getPublicModelHubInfo: vi.fn().mockResolvedValue({
docs_title: "LiteLLM Gateway",
custom_docs_description: null,
litellm_version: "1.0.0",
useful_links: {},
}),
agentHubPublicModelsCall: vi.fn().mockResolvedValue([]),
mcpHubPublicServersCall: vi.fn().mockResolvedValue([]),
getUiConfig: vi.fn().mockResolvedValue({}),
};
});
beforeAll(() => {
Object.defineProperty(window, "matchMedia", {
writable: true,
value: (query: string) => ({
matches: false,
media: query,
onchange: null,
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: () => false,
}),
});
});
beforeEach(() => {
Storage.prototype.getItem = vi.fn(() => "false");
Storage.prototype.setItem = vi.fn();
Object.defineProperty(window, "location", {
writable: true,
value: {
pathname: "/",
origin: "http://localhost:3000",
},
});
});
describe("PublicModelHub", () => {
it("renders", () => {
const { container } = render(
<FeatureFlagsProvider>
<PublicModelHub />
</FeatureFlagsProvider>,
);
expect(container).toBeInTheDocument();
});
});

View file

@ -1,5 +1,11 @@
import React, { useEffect, useState, useRef, useMemo } from "react";
import { modelHubPublicModelsCall, getPublicModelHubInfo, agentHubPublicModelsCall, mcpHubPublicServersCall } from "./networking";
import {
modelHubPublicModelsCall,
getPublicModelHubInfo,
agentHubPublicModelsCall,
mcpHubPublicServersCall,
getUiConfig,
} from "./networking";
import { ModelDataTable } from "./model_dashboard/table";
import { ColumnDef } from "@tanstack/react-table";
import { Card, Text, Title, Button } from "@tremor/react";
@ -117,60 +123,72 @@ const PublicModelHub: React.FC<PublicModelHubProps> = ({ accessToken, isEmbedded
const mcpTableRef = useRef<TableInstance<any>>(null);
useEffect(() => {
const fetchPublicData = async () => {
const initializeAndFetch = async () => {
// Initialize proxyBaseUrl first to ensure it includes the server root path
try {
setLoading(true);
const _modelHubData = await modelHubPublicModelsCall();
console.log("ModelHubData:", _modelHubData);
setModelHubData(_modelHubData);
await getUiConfig();
} catch (error) {
console.error("There was an error fetching the public model data", error);
setServiceStatus("Service unavailable");
} finally {
setLoading(false);
console.error("Failed to get UI config:", error);
// Continue anyway - might work with default proxyBaseUrl
}
const fetchPublicData = async () => {
try {
setLoading(true);
const _modelHubData = await modelHubPublicModelsCall();
console.log("ModelHubData:", _modelHubData);
setModelHubData(_modelHubData);
} catch (error) {
console.error("There was an error fetching the public model data", error);
setServiceStatus("Service unavailable");
} finally {
setLoading(false);
}
};
const fetchAgentData = async () => {
try {
setAgentLoading(true);
const _agentHubData = await agentHubPublicModelsCall();
console.log("AgentHubData:", _agentHubData);
setAgentHubData(_agentHubData);
} catch (error) {
console.error("There was an error fetching the public agent data", error);
} finally {
setAgentLoading(false);
}
};
const fetchMcpData = async () => {
try {
setMcpLoading(true);
const _mcpHubData = await mcpHubPublicServersCall();
console.log("MCPHubData:", _mcpHubData);
setMcpHubData(_mcpHubData);
} catch (error) {
console.error("There was an error fetching the public MCP server data", error);
} finally {
setMcpLoading(false);
}
};
const fetchPublicModelHubInfo = async () => {
const publicModelHubInfo = await getPublicModelHubInfo();
console.log("Public Model Hub Info:", publicModelHubInfo);
setPageTitle(publicModelHubInfo.docs_title);
setCustomDocsDescription(publicModelHubInfo.custom_docs_description);
setLitellmVersion(publicModelHubInfo.litellm_version);
setUsefulLinks(publicModelHubInfo.useful_links || {});
};
fetchPublicModelHubInfo();
fetchPublicData();
fetchAgentData();
fetchMcpData();
};
const fetchAgentData = async () => {
try {
setAgentLoading(true);
const _agentHubData = await agentHubPublicModelsCall();
console.log("AgentHubData:", _agentHubData);
setAgentHubData(_agentHubData);
} catch (error) {
console.error("There was an error fetching the public agent data", error);
} finally {
setAgentLoading(false);
}
};
const fetchMcpData = async () => {
try {
setMcpLoading(true);
const _mcpHubData = await mcpHubPublicServersCall();
console.log("MCPHubData:", _mcpHubData);
setMcpHubData(_mcpHubData);
} catch (error) {
console.error("There was an error fetching the public MCP server data", error);
} finally {
setMcpLoading(false);
}
};
const fetchPublicModelHubInfo = async () => {
const publicModelHubInfo = await getPublicModelHubInfo();
console.log("Public Model Hub Info:", publicModelHubInfo);
setPageTitle(publicModelHubInfo.docs_title);
setCustomDocsDescription(publicModelHubInfo.custom_docs_description);
setLitellmVersion(publicModelHubInfo.litellm_version);
setUsefulLinks(publicModelHubInfo.useful_links || {});
};
fetchPublicModelHubInfo();
fetchPublicData();
fetchAgentData();
fetchMcpData();
initializeAndFetch();
}, []);
// Clear filters when filter values change to avoid confusion
@ -400,8 +418,7 @@ const PublicModelHub: React.FC<PublicModelHubProps> = ({ accessToken, isEmbedded
// Apply transport filters
return searchResults.filter((server) => {
const matchesTransport =
selectedMcpTransports.length === 0 || selectedMcpTransports.includes(server.transport);
const matchesTransport = selectedMcpTransports.length === 0 || selectedMcpTransports.includes(server.transport);
return matchesTransport;
});
@ -1183,10 +1200,7 @@ const PublicModelHub: React.FC<PublicModelHubProps> = ({ accessToken, isEmbedded
<div>
<div className="flex items-center space-x-2 mb-3">
<Text className="text-sm font-medium text-gray-700">Search MCP Servers:</Text>
<Tooltip
title="Search MCP servers by name or description"
placement="top"
>
<Tooltip title="Search MCP servers by name or description" placement="top">
<Info className="w-4 h-4 text-gray-400 cursor-help" />
</Tooltip>
</div>
@ -1842,9 +1856,7 @@ print(response.model_dump(mode='json', exclude_none=True))`;
<div>
<Text className="text-lg font-semibold mb-4">Additional Information</Text>
<div className="bg-gray-50 p-4 rounded-lg">
<pre className="text-xs overflow-x-auto">
{JSON.stringify(selectedMcpServer.mcp_info, null, 2)}
</pre>
<pre className="text-xs overflow-x-auto">{JSON.stringify(selectedMcpServer.mcp_info, null, 2)}</pre>
</div>
</div>
)}
@ -1854,7 +1866,7 @@ print(response.model_dump(mode='json', exclude_none=True))`;
<Text className="text-lg font-semibold mb-4">Usage Example</Text>
<div className="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto">
<pre className="text-sm">
{`# Using MCP Server with Python FastMCP
{`# Using MCP Server with Python FastMCP
from fastmcp import Client
import asyncio