working showing user the raw request / response

This commit is contained in:
Ishaan Jaff 2025-03-14 16:39:48 -07:00
parent a1f5002638
commit cdd625972c
3 changed files with 115 additions and 68 deletions

View file

@ -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<string, any>;
accessToken: string;
testMode: string;
modelName?: string;
onClose?: () => void;
}
const ConnectionErrorDisplay: React.FC<ConnectionErrorDisplayProps> = ({
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<Error | string | null>(null);
const [rawRequest, setRawRequest] = React.useState<any>(null);
const [rawResponse, setRawResponse] = React.useState<any>(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<string, any>, requestHeaders: Record<string, string>) => {
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 (
<div style={{ padding: '16px 24px' }}>
{/* Use the ErrorViewer component for consistent error display */}
<ErrorViewer errorInfo={errorInfo} />
<Divider style={{ margin: '16px 0' }} />
<div style={{ display: 'flex', justifyContent: 'flex-start' }}>
<Button
type="link"
href="https://docs.litellm.ai/docs/providers"
target="_blank"
icon={<InfoCircleOutlined />}
>
View Documentation
</Button>
<div style={{ padding: '16px 24px' }}>
<Divider style={{ margin: '16px 0' }} />
{error && (
<div>
<Text type="danger">{errorMessage}</Text>
<Divider style={{ margin: '16px 0' }} />
<div>
<h3>Raw Request</h3>
<pre style={{ backgroundColor: '#f5f5f5', padding: '16px', borderRadius: '6px' }}>
{curlCommand || "No request data"}
</pre>
<Button
type="text"
icon={<CopyOutlined />}
onClick={() => {
navigator.clipboard.writeText(curlCommand || '');
message.success('Copied to clipboard');
}}
>
Copy to Clipboard
</Button>
</div>
</div>
)}
<Divider style={{ margin: '16px 0' }} />
<div style={{ display: 'flex', justifyContent: 'flex-start' }}>
<Button
type="link"
href="https://docs.litellm.ai/docs/providers"
target="_blank"
icon={<InfoCircleOutlined />}
>
View Documentation
</Button>
</div>
</div>
);
};

View file

@ -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<AddModelTabProps> = ({
const [isTestModalVisible, setIsTestModalVisible] = useState<boolean>(false);
const [connectionError, setConnectionError] = useState<Error | string | null>(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<AddModelTabProps> = ({
<Button
key="test"
type="primary"
onClick={handleTestConnection}
onClick={() => setConnectionError("Test connection logic is now in ConnectionErrorDisplay")}
loading={false} // You might want to add a loading state
>
Test Connection
@ -281,8 +260,11 @@ const AddModelTab: React.FC<AddModelTabProps> = ({
<Typography.Title level={5} type="danger">Connection Test Failed</Typography.Title>
<div className="border border-red-300 rounded-md overflow-hidden">
<ConnectionErrorDisplay
error={connectionError}
modelName={form.getFieldValue('model_name') || form.getFieldValue('model')}
formValues={form.getFieldsValue()}
accessToken={accessToken}
testMode={testMode}
modelName={form.getFieldValue('model_name') || form.getFieldValue('model')}
onClose={() => setIsTestModalVisible(false)}
/>
</div>
</div>

View file

@ -6,7 +6,7 @@ export const testModelConnection = async (
formValues: Record<string, any>,
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);
}