diff --git a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx
index 4590121acf..c2b730bf46 100644
--- a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx
+++ b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx
@@ -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(
+
+
+ ,
+ );
+
+ 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(
+
+
+ ,
+ );
+
+ 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(
+
+
+ ,
+ );
+
+ 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(
+
+
+ ,
+ );
+
+ 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");
+ });
+ });
});
diff --git a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx
index 24df0ac21e..045a9b0c1b 100644
--- a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx
+++ b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.tsx
@@ -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 = ({ selecte
return mapped;
}, [selectedProviderEnum, selectedProvider, providerMetadata]);
+ const hasApiVersionField = React.useMemo(() => allFields.some((field) => field.key === "api_version"), [allFields]);
+ const lastInferredApiVersionRef = React.useRef(null);
+
+ const handleApiBaseChange = React.useCallback(
+ (event: React.ChangeEvent) => {
+ 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 = ({ selecte
placeholder={field.placeholder}
type={field.type === "password" ? "password" : "text"}
defaultValue={field.defaultValue}
+ onChange={field.key === "api_base" ? handleApiBaseChange : undefined}
/>
)}