mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-07 06:29:41 +00:00
fix(ui): infer Azure API version from API base (#30204)
* fix(ui): infer Azure API version from API base * fix(ui): address Azure API version feedback
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { Form } from "antd";
|
||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { Providers } from "../provider_info_helpers";
|
||||
@@ -215,4 +215,134 @@ describe("ProviderSpecificFields", () => {
|
||||
expect(baseModelInput).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("sets Azure API version from the API base query parameter", async () => {
|
||||
const queryClient = createQueryClient();
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Form>
|
||||
<ProviderSpecificFields selectedProvider={Providers.Azure} />
|
||||
</Form>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
|
||||
const apiBaseInput = await screen.findByPlaceholderText("https://...");
|
||||
const apiVersionInput = await screen.findByPlaceholderText("2023-07-01-preview");
|
||||
|
||||
fireEvent.change(apiBaseInput, {
|
||||
target: {
|
||||
value:
|
||||
"https://test-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions?api_version=2024-10-21",
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiVersionInput).toHaveValue("2024-10-21");
|
||||
});
|
||||
});
|
||||
|
||||
it("sets Azure API version from the hyphenated API base query parameter", async () => {
|
||||
const queryClient = createQueryClient();
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Form>
|
||||
<ProviderSpecificFields selectedProvider={Providers.Azure} />
|
||||
</Form>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
|
||||
const apiBaseInput = await screen.findByPlaceholderText("https://...");
|
||||
const apiVersionInput = await screen.findByPlaceholderText("2023-07-01-preview");
|
||||
|
||||
fireEvent.change(apiBaseInput, {
|
||||
target: {
|
||||
value:
|
||||
"https://test-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2024-10-21",
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiVersionInput).toHaveValue("2024-10-21");
|
||||
});
|
||||
});
|
||||
|
||||
it("clears an inferred Azure API version when the API base has no version parameter", async () => {
|
||||
const queryClient = createQueryClient();
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Form>
|
||||
<ProviderSpecificFields selectedProvider={Providers.Azure} />
|
||||
</Form>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
|
||||
const apiBaseInput = await screen.findByPlaceholderText("https://...");
|
||||
const apiVersionInput = await screen.findByPlaceholderText("2023-07-01-preview");
|
||||
|
||||
fireEvent.change(apiBaseInput, {
|
||||
target: {
|
||||
value:
|
||||
"https://test-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2024-10-21",
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiVersionInput).toHaveValue("2024-10-21");
|
||||
});
|
||||
|
||||
fireEvent.change(apiBaseInput, {
|
||||
target: {
|
||||
value: "https://test-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions",
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiVersionInput).toHaveValue("");
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves a manually edited Azure API version when the API base has no version parameter", async () => {
|
||||
const queryClient = createQueryClient();
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Form>
|
||||
<ProviderSpecificFields selectedProvider={Providers.Azure} />
|
||||
</Form>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
|
||||
const apiBaseInput = await screen.findByPlaceholderText("https://...");
|
||||
const apiVersionInput = await screen.findByPlaceholderText("2023-07-01-preview");
|
||||
|
||||
fireEvent.change(apiBaseInput, {
|
||||
target: {
|
||||
value:
|
||||
"https://test-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2024-10-21",
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiVersionInput).toHaveValue("2024-10-21");
|
||||
});
|
||||
|
||||
fireEvent.change(apiVersionInput, {
|
||||
target: {
|
||||
value: "2025-01-01-preview",
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiVersionInput).toHaveValue("2025-01-01-preview");
|
||||
});
|
||||
|
||||
fireEvent.change(apiBaseInput, {
|
||||
target: {
|
||||
value: "https://test-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions",
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiVersionInput).toHaveValue("2025-01-01-preview");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,6 +28,18 @@ export interface CredentialValues {
|
||||
value: string;
|
||||
}
|
||||
|
||||
const getApiVersionFromApiBase = (apiBase: string): string | null => {
|
||||
const queryStartIndex = apiBase.indexOf("?");
|
||||
if (queryStartIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const queryString = apiBase.slice(queryStartIndex + 1).split("#")[0];
|
||||
const searchParams = new URLSearchParams(queryString);
|
||||
|
||||
return searchParams.get("api_version") || searchParams.get("api-version");
|
||||
};
|
||||
|
||||
const mapFieldMetadataToUiField = (field: ProviderCredentialFieldMetadata): ProviderCredentialField => {
|
||||
const type: ProviderCredentialField["type"] =
|
||||
field.field_type === "password"
|
||||
@@ -167,6 +179,30 @@ const ProviderSpecificFields: React.FC<ProviderSpecificFieldsProps> = ({ selecte
|
||||
return mapped;
|
||||
}, [selectedProviderEnum, selectedProvider, providerMetadata]);
|
||||
|
||||
const hasApiVersionField = React.useMemo(() => allFields.some((field) => field.key === "api_version"), [allFields]);
|
||||
const lastInferredApiVersionRef = React.useRef<string | null>(null);
|
||||
|
||||
const handleApiBaseChange = React.useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!hasApiVersionField) {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiVersion = getApiVersionFromApiBase(event.target.value);
|
||||
if (apiVersion) {
|
||||
lastInferredApiVersionRef.current = apiVersion;
|
||||
form.setFieldsValue({ api_version: apiVersion });
|
||||
return;
|
||||
}
|
||||
|
||||
if (form.getFieldValue("api_version") === lastInferredApiVersionRef.current) {
|
||||
form.setFieldsValue({ api_version: "" });
|
||||
}
|
||||
lastInferredApiVersionRef.current = null;
|
||||
},
|
||||
[form, hasApiVersionField],
|
||||
);
|
||||
|
||||
const handleUpload = {
|
||||
name: "file",
|
||||
accept: ".json",
|
||||
@@ -261,6 +297,7 @@ const ProviderSpecificFields: React.FC<ProviderSpecificFieldsProps> = ({ selecte
|
||||
placeholder={field.placeholder}
|
||||
type={field.type === "password" ? "password" : "text"}
|
||||
defaultValue={field.defaultValue}
|
||||
onChange={field.key === "api_base" ? handleApiBaseChange : undefined}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
Reference in New Issue
Block a user