mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
Merge pull request #18661 from Chesars/litellm_ui_custom_proxy_base_url
feat(ui): add custom proxy base URL support to Playground
This commit is contained in:
commit
8acb9bf366
12 changed files with 90 additions and 15 deletions
|
|
@ -130,6 +130,9 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
return disabledPersonalKeyCreation ? "custom" : "session";
|
||||
});
|
||||
const [apiKey, setApiKey] = useState<string>(() => sessionStorage.getItem("apiKey") || "");
|
||||
const [customProxyBaseUrl, setCustomProxyBaseUrl] = useState<string>(
|
||||
() => sessionStorage.getItem("customProxyBaseUrl") || ""
|
||||
);
|
||||
const [inputMessage, setInputMessage] = useState("");
|
||||
const [chatHistory, setChatHistory] = useState<MessageType[]>(() => {
|
||||
try {
|
||||
|
|
@ -392,7 +395,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
|
||||
const loadAgents = async () => {
|
||||
try {
|
||||
const agents = await fetchAvailableAgents(userApiKey);
|
||||
const agents = await fetchAvailableAgents(userApiKey, customProxyBaseUrl || undefined);
|
||||
setAgentInfo(agents);
|
||||
// Clear selection if current agent not in list
|
||||
if (selectedAgent && !agents.some((a) => a.agent_name === selectedAgent)) {
|
||||
|
|
@ -404,7 +407,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
};
|
||||
|
||||
loadAgents();
|
||||
}, [accessToken, apiKeySource, apiKey, endpointType]);
|
||||
}, [accessToken, apiKeySource, apiKey, endpointType, customProxyBaseUrl, selectedAgent]);
|
||||
|
||||
useEffect(() => {
|
||||
// Scroll to the bottom of the chat whenever chatHistory updates
|
||||
|
|
@ -900,6 +903,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
useAdvancedParams ? temperature : undefined,
|
||||
useAdvancedParams ? maxTokens : undefined,
|
||||
updateTotalLatency,
|
||||
customProxyBaseUrl || undefined,
|
||||
mcpServers,
|
||||
mcpServerToolRestrictions,
|
||||
);
|
||||
|
|
@ -912,6 +916,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
effectiveApiKey,
|
||||
selectedTags,
|
||||
signal,
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
} else if (endpointType === EndpointType.SPEECH) {
|
||||
// For audio speech
|
||||
|
|
@ -923,6 +928,9 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
effectiveApiKey,
|
||||
selectedTags,
|
||||
signal,
|
||||
undefined, // responseFormat
|
||||
undefined, // speed
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
} else if (endpointType === EndpointType.IMAGE_EDITS) {
|
||||
// For image edits
|
||||
|
|
@ -935,6 +943,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
effectiveApiKey,
|
||||
selectedTags,
|
||||
signal,
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
}
|
||||
} else if (endpointType === EndpointType.RESPONSES) {
|
||||
|
|
@ -973,6 +982,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
handleMCPEvent, // Pass MCP event handler
|
||||
codeInterpreter.enabled, // Enable Code Interpreter tool
|
||||
codeInterpreter.setResult, // Handle code interpreter output
|
||||
customProxyBaseUrl || undefined,
|
||||
mcpServers,
|
||||
mcpServerToolRestrictions,
|
||||
);
|
||||
|
|
@ -997,6 +1007,8 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
traceId,
|
||||
selectedVectorStores.length > 0 ? selectedVectorStores : undefined,
|
||||
selectedGuardrails.length > 0 ? selectedGuardrails : undefined,
|
||||
selectedMCPTools, // Pass the selected tools array
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
} else if (endpointType === EndpointType.EMBEDDINGS) {
|
||||
await makeOpenAIEmbeddingsRequest(
|
||||
|
|
@ -1005,6 +1017,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
selectedModel,
|
||||
effectiveApiKey,
|
||||
selectedTags,
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
} else if (endpointType === EndpointType.TRANSCRIPTION) {
|
||||
// For audio transcriptions
|
||||
|
|
@ -1016,6 +1029,11 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
effectiveApiKey,
|
||||
selectedTags,
|
||||
signal,
|
||||
undefined, // language
|
||||
undefined, // prompt
|
||||
undefined, // responseFormat
|
||||
undefined, // temperature
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1032,6 +1050,7 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
updateTimingData,
|
||||
updateTotalLatency,
|
||||
updateA2AMetadata,
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -1156,6 +1175,42 @@ const ChatUI: React.FC<ChatUIProps> = ({
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<Text className="font-medium text-gray-700 flex items-center">
|
||||
<SettingOutlined className="mr-2" /> Custom Proxy Base URL
|
||||
</Text>
|
||||
{customProxyBaseUrl && (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<ClearOutlined />}
|
||||
onClick={() => {
|
||||
setCustomProxyBaseUrl("");
|
||||
sessionStorage.removeItem("customProxyBaseUrl");
|
||||
}}
|
||||
className="text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<TextInput
|
||||
placeholder="Optional: Enter custom proxy URL (e.g., http://localhost:5000)"
|
||||
onValueChange={(value) => {
|
||||
setCustomProxyBaseUrl(value);
|
||||
sessionStorage.setItem("customProxyBaseUrl", value);
|
||||
}}
|
||||
value={customProxyBaseUrl}
|
||||
icon={ApiOutlined}
|
||||
/>
|
||||
{customProxyBaseUrl && (
|
||||
<Text className="text-xs text-gray-500 mt-1">
|
||||
API calls will be sent to: {customProxyBaseUrl}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text className="font-medium block mb-2 text-gray-700 flex items-center">
|
||||
<ApiOutlined className="mr-2" /> Endpoint Type
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@ export default function CompareUI({ accessToken, disabledPersonalKeyCreation }:
|
|||
);
|
||||
const [customApiKey, setCustomApiKey] = useState("");
|
||||
const [debouncedCustomApiKey, setDebouncedCustomApiKey] = useState("");
|
||||
const [customProxyBaseUrl] = useState<string>(
|
||||
() => sessionStorage.getItem("customProxyBaseUrl") || ""
|
||||
);
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setDebouncedCustomApiKey(customApiKey);
|
||||
|
|
@ -171,7 +174,7 @@ export default function CompareUI({ accessToken, disabledPersonalKeyCreation }:
|
|||
}
|
||||
setIsLoadingAgents(true);
|
||||
try {
|
||||
const agents = await fetchAvailableAgents(effectiveApiKey);
|
||||
const agents = await fetchAvailableAgents(effectiveApiKey, customProxyBaseUrl || undefined);
|
||||
if (!active) return;
|
||||
setAgentOptions(agents);
|
||||
} catch (error) {
|
||||
|
|
@ -598,6 +601,8 @@ export default function CompareUI({ accessToken, disabledPersonalKeyCreation }:
|
|||
undefined,
|
||||
(time) => updateTimingDataForComparison(prepared.id, time),
|
||||
(latency) => updateTotalLatencyForComparison(prepared.id, latency),
|
||||
undefined, // onA2AMetadata
|
||||
customProxyBaseUrl || undefined,
|
||||
)
|
||||
: makeOpenAIChatCompletionRequest(
|
||||
prepared.apiChatHistory,
|
||||
|
|
@ -618,6 +623,7 @@ export default function CompareUI({ accessToken, disabledPersonalKeyCreation }:
|
|||
useAdvancedParams ? prepared.temperature : undefined,
|
||||
useAdvancedParams ? prepared.maxTokens : undefined,
|
||||
(latency) => updateTotalLatencyForComparison(prepared.id, latency),
|
||||
customProxyBaseUrl || undefined,
|
||||
);
|
||||
|
||||
requestPromise
|
||||
|
|
|
|||
|
|
@ -113,8 +113,9 @@ export const makeA2ASendMessageRequest = async (
|
|||
onTimingData?: (timeToFirstToken: number) => void,
|
||||
onTotalLatency?: (totalLatency: number) => void,
|
||||
onA2AMetadata?: (metadata: A2ATaskMetadata) => void,
|
||||
customBaseUrl?: string,
|
||||
): Promise<void> => {
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
const url = proxyBaseUrl
|
||||
? `${proxyBaseUrl}/a2a/${agentId}/message/send`
|
||||
: `/a2a/${agentId}/message/send`;
|
||||
|
|
@ -242,8 +243,9 @@ export const makeA2AStreamMessageRequest = async (
|
|||
onTimingData?: (timeToFirstToken: number) => void,
|
||||
onTotalLatency?: (totalLatency: number) => void,
|
||||
onA2AMetadata?: (metadata: A2ATaskMetadata) => void,
|
||||
customBaseUrl?: string,
|
||||
): Promise<void> => {
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
const url = proxyBaseUrl
|
||||
? `${proxyBaseUrl}/a2a/${agentId}`
|
||||
: `/a2a/${agentId}`;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ export async function makeAnthropicMessagesRequest(
|
|||
traceId?: string,
|
||||
vector_store_ids?: string[],
|
||||
guardrails?: string[],
|
||||
selectedMCPTools?: string[],
|
||||
customBaseUrl?: string,
|
||||
) {
|
||||
if (!accessToken) {
|
||||
throw new Error("Virtual Key is required");
|
||||
|
|
@ -27,7 +29,7 @@ export async function makeAnthropicMessagesRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
|
||||
// Prepare headers with tags and trace ID
|
||||
const headers: Record<string, string> = {};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export async function makeOpenAIAudioSpeechRequest(
|
|||
signal?: AbortSignal,
|
||||
responseFormat?: string,
|
||||
speed?: number,
|
||||
customBaseUrl?: string,
|
||||
) {
|
||||
// base url should be the current base_url
|
||||
const isLocal = process.env.NODE_ENV === "development";
|
||||
|
|
@ -20,7 +21,7 @@ export async function makeOpenAIAudioSpeechRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
console.log("isLocal:", isLocal);
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
const client = new openai.OpenAI({
|
||||
apiKey: accessToken,
|
||||
baseURL: proxyBaseUrl,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export async function makeOpenAIAudioTranscriptionRequest(
|
|||
prompt?: string,
|
||||
responseFormat?: string,
|
||||
temperature?: number,
|
||||
customBaseUrl?: string,
|
||||
) {
|
||||
// base url should be the current base_url
|
||||
const isLocal = process.env.NODE_ENV === "development";
|
||||
|
|
@ -20,7 +21,7 @@ export async function makeOpenAIAudioTranscriptionRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
console.log("isLocal:", isLocal);
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
|
||||
const client = new openai.OpenAI({
|
||||
apiKey: accessToken,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export async function makeOpenAIChatCompletionRequest(
|
|||
temperature?: number,
|
||||
max_tokens?: number,
|
||||
onTotalLatency?: (latency: number) => void,
|
||||
customBaseUrl?: string,
|
||||
mcpServers?: MCPServer[],
|
||||
mcpServerToolRestrictions?: Record<string, string[]>,
|
||||
) {
|
||||
|
|
@ -33,7 +34,7 @@ export async function makeOpenAIChatCompletionRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
console.log("isLocal:", isLocal);
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
// Prepare headers with tags and trace ID
|
||||
const headers: Record<string, string> = {};
|
||||
if (tags && tags.length > 0) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export async function makeOpenAIEmbeddingsRequest(
|
|||
selectedModel: string,
|
||||
accessToken: string,
|
||||
tags?: string[],
|
||||
customBaseUrl?: string,
|
||||
) {
|
||||
if (!accessToken) {
|
||||
throw new Error("Virtual Key is required");
|
||||
|
|
@ -18,7 +19,7 @@ export async function makeOpenAIEmbeddingsRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
// Prepare headers with tags and trace ID
|
||||
const headers: Record<string, string> = {};
|
||||
if (tags && tags.length > 0) {
|
||||
|
|
|
|||
|
|
@ -16,9 +16,12 @@ export interface Agent {
|
|||
/**
|
||||
* Fetches available A2A agents from /v1/agents endpoint.
|
||||
*/
|
||||
export const fetchAvailableAgents = async (accessToken: string): Promise<Agent[]> => {
|
||||
export const fetchAvailableAgents = async (
|
||||
accessToken: string,
|
||||
customBaseUrl?: string,
|
||||
): Promise<Agent[]> => {
|
||||
try {
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/v1/agents` : `/v1/agents`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export async function makeOpenAIImageEditsRequest(
|
|||
accessToken: string,
|
||||
tags?: string[],
|
||||
signal?: AbortSignal,
|
||||
customBaseUrl?: string,
|
||||
) {
|
||||
// base url should be the current base_url
|
||||
const isLocal = process.env.NODE_ENV === "development";
|
||||
|
|
@ -17,7 +18,7 @@ export async function makeOpenAIImageEditsRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
console.log("isLocal:", isLocal);
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
|
||||
const client = new openai.OpenAI({
|
||||
apiKey: accessToken,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export async function makeOpenAIImageGenerationRequest(
|
|||
accessToken: string,
|
||||
tags?: string[],
|
||||
signal?: AbortSignal,
|
||||
customBaseUrl?: string,
|
||||
) {
|
||||
// base url should be the current base_url
|
||||
const isLocal = process.env.NODE_ENV === "development";
|
||||
|
|
@ -16,7 +17,7 @@ export async function makeOpenAIImageGenerationRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
console.log("isLocal:", isLocal);
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
const client = new openai.OpenAI({
|
||||
apiKey: accessToken,
|
||||
baseURL: proxyBaseUrl,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export async function makeOpenAIResponsesRequest(
|
|||
onMCPEvent?: (event: MCPEvent) => void,
|
||||
codeInterpreterEnabled?: boolean,
|
||||
onCodeInterpreterResult?: (result: CodeInterpreterResult) => void,
|
||||
customBaseUrl?: string,
|
||||
mcpServers?: MCPServer[],
|
||||
mcpServerToolRestrictions?: Record<string, string[]>,
|
||||
) {
|
||||
|
|
@ -50,7 +51,7 @@ export async function makeOpenAIResponsesRequest(
|
|||
console.log = function () {};
|
||||
}
|
||||
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const proxyBaseUrl = customBaseUrl || getProxyBaseUrl();
|
||||
// Prepare headers with tags and trace ID
|
||||
const headers: Record<string, string> = {};
|
||||
if (tags && tags.length > 0) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue