From cdd625972c9e19ff8f2f12dc2f2c6d84c3b95126 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 14 Mar 2025 16:39:48 -0700 Subject: [PATCH] working showing user the raw request / response --- .../add_model/ConnectionErrorDisplay.tsx | 136 +++++++++++++----- .../components/add_model/add_model_tab.tsx | 30 +--- .../add_model/test_connection_handler.tsx | 17 ++- 3 files changed, 115 insertions(+), 68 deletions(-) diff --git a/ui/litellm-dashboard/src/components/add_model/ConnectionErrorDisplay.tsx b/ui/litellm-dashboard/src/components/add_model/ConnectionErrorDisplay.tsx index de3a057c329..69f1becdc05 100644 --- a/ui/litellm-dashboard/src/components/add_model/ConnectionErrorDisplay.tsx +++ b/ui/litellm-dashboard/src/components/add_model/ConnectionErrorDisplay.tsx @@ -1,55 +1,121 @@ import React from 'react'; -import { Typography, Space, Button, Divider } from 'antd'; -import { WarningOutlined, InfoCircleOutlined } from '@ant-design/icons'; -import { ErrorViewer } from '../view_logs/ErrorViewer'; +import { Typography, Space, Button, Divider, message } from 'antd'; +import { WarningOutlined, InfoCircleOutlined, CopyOutlined } from '@ant-design/icons'; +import { testConnectionRequest } from "../networking"; +import { prepareModelAddRequest } from "./handle_add_model_submit"; const { Text } = Typography; interface ConnectionErrorDisplayProps { - error: Error | string; + formValues: Record; + accessToken: string; + testMode: string; modelName?: string; onClose?: () => void; } const ConnectionErrorDisplay: React.FC = ({ - error, - modelName = "this model", + formValues, + accessToken, + testMode, + modelName = "this model", onClose }) => { - const errorMessage = typeof error === 'string' ? error : error.message; - - // Create an error info object compatible with ErrorViewer - const errorInfo = { - error_message: errorMessage.split('\n')[0], - traceback: errorMessage, - // We don't have these fields from the connection test error, but the component handles undefined - error_class: undefined, - llm_provider: undefined, - error_code: undefined + const [error, setError] = React.useState(null); + const [rawRequest, setRawRequest] = React.useState(null); + const [rawResponse, setRawResponse] = React.useState(null); + + const testModelConnection = async () => { + try { + const result = await prepareModelAddRequest(formValues, accessToken, null); + if (!result) throw new Error("Failed to prepare model data"); + + const { litellmParamsObj } = result; + const requestBody = { ...litellmParamsObj, mode: testMode }; + + const response = await testConnectionRequest(accessToken, requestBody); + if (response.status === "success") { + message.success("Connection test successful!"); + setError(null); + } else { + const errorMessage = response.result?.error || response.message || "Unknown error"; + setError(errorMessage); + setRawRequest(requestBody); + setRawResponse(response.result?.raw_request_typed_dict); + } + } catch (error) { + console.error("Test connection error:", error); + setError(error instanceof Error ? error.message : String(error)); + } }; + React.useEffect(() => { + testModelConnection(); + }, []); + + const errorMessage = typeof error === 'string' ? error : error?.message; + + const formatCurlCommand = (apiBase: string, requestBody: Record, requestHeaders: Record) => { + const formattedBody = JSON.stringify(requestBody, null, 2) + .split('\n') + .map(line => ` ${line}`) + .join('\n'); + + const headerString = Object.entries(requestHeaders) + .map(([key, value]) => `-H '${key}: ${value}'`) + .join(' \\\n '); + + return `curl -X POST \\ + ${apiBase} \\ + ${headerString ? `${headerString} \\\n ` : ''}-H 'Content-Type: application/json' \\ + -d '{ +${formattedBody} + }'`; + }; + + const curlCommand = rawResponse ? formatCurlCommand( + rawResponse.raw_request_api_base, + rawResponse.raw_request_body, + rawResponse.raw_request_headers || {} + ) : ''; + return ( - -
- - - {/* Use the ErrorViewer component for consistent error display */} - - - - -
- +
+ + {error && ( +
+ {errorMessage} + +
+

Raw Request

+
+              {curlCommand || "No request data"}
+            
+ +
+ )} + +
+
- +
); }; diff --git a/ui/litellm-dashboard/src/components/add_model/add_model_tab.tsx b/ui/litellm-dashboard/src/components/add_model/add_model_tab.tsx index 521d84d6dfe..0760afd4dd9 100644 --- a/ui/litellm-dashboard/src/components/add_model/add_model_tab.tsx +++ b/ui/litellm-dashboard/src/components/add_model/add_model_tab.tsx @@ -9,7 +9,6 @@ import AdvancedSettings from "./advanced_settings"; import { Providers, providerLogoMap, getPlaceholder } from "../provider_info_helpers"; import type { Team } from "../key_team_helpers/key_list"; import { CredentialItem } from "../networking"; -import { testModelConnection } from "./test_connection_handler"; import ConnectionErrorDisplay from "./ConnectionErrorDisplay"; interface AddModelTabProps { @@ -61,26 +60,6 @@ const AddModelTab: React.FC = ({ const [isTestModalVisible, setIsTestModalVisible] = useState(false); const [connectionError, setConnectionError] = useState(null); - // Add a function to handle test connection - const handleTestConnection = async () => { - // Clear any previous errors - setConnectionError(null); - - try { - const formValues = form.getFieldsValue(); - - // Call the existing testModelConnection function - const result = await testModelConnection(formValues, accessToken, testMode, setConnectionError); - - // Only close the modal on success - if (result && result.status === "success") { - setIsTestModalVisible(false); - } - } catch (error) { - console.error("Test connection failed:", error); - } - }; - // Show test modal with mode selection const showTestModal = () => { setConnectionError(null); @@ -252,7 +231,7 @@ const AddModelTab: React.FC = ({
diff --git a/ui/litellm-dashboard/src/components/add_model/test_connection_handler.tsx b/ui/litellm-dashboard/src/components/add_model/test_connection_handler.tsx index 7376ee06c45..d0b7e85dd47 100644 --- a/ui/litellm-dashboard/src/components/add_model/test_connection_handler.tsx +++ b/ui/litellm-dashboard/src/components/add_model/test_connection_handler.tsx @@ -6,7 +6,7 @@ export const testModelConnection = async ( formValues: Record, accessToken: string, testMode: string, - setConnectionError?: (error: Error | string | null) => void + setConnectionError?: (error: Error | string | null, rawRequest?: any, rawResponse?: any) => void ) => { try { // Prepare the model data using the existing function @@ -20,30 +20,30 @@ export const testModelConnection = async ( // Create the request body for the test connection const requestBody = { - ...litellmParamsObj, // Unfurl the parameters directly + ...litellmParamsObj, mode: testMode }; + console.log("Request Body:", requestBody); // Debugging log + // Call the test connection endpoint const response = await testConnectionRequest(accessToken, requestBody); + console.log("Response:", response); // Debugging log + if (response.status === "success") { message.success("Connection test successful!"); - // Clear any previous error when successful if (setConnectionError) { setConnectionError(null); } } else { - // Extract the detailed error message from the response let errorMessage = response.message || "Unknown error"; - - // Check if there's a more detailed error in the result if (response.result && response.result.error) { errorMessage = response.result.error; } if (setConnectionError) { - setConnectionError(errorMessage); + setConnectionError(errorMessage, requestBody, response.result.raw_request_typed_dict); } else { message.error("Connection test failed: " + errorMessage); } @@ -53,9 +53,8 @@ export const testModelConnection = async ( } catch (error) { console.error("Test connection error:", error); - // Set the error for ConnectionErrorDisplay if (setConnectionError) { - setConnectionError(error); + setConnectionError(error, requestBody, null); } else { message.error("Test connection failed: " + error, 10); }