diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json
index e22812df465..7de7373b20b 100644
--- a/ui/litellm-dashboard/eslint-suppressions.json
+++ b/ui/litellm-dashboard/eslint-suppressions.json
@@ -1465,9 +1465,6 @@
"src/components/add_model/conditional_public_model_name.tsx": {
"local/filename-pascal-case": {
"count": 1
- },
- "local/no-complex-jsx-arrow": {
- "count": 1
}
},
"src/components/add_model/handle_add_auto_router_submit.tsx": {
diff --git a/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.test.tsx b/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.test.tsx
index 07ec36639b4..a4a9da87847 100644
--- a/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.test.tsx
+++ b/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.test.tsx
@@ -1,4 +1,5 @@
import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
import React, { useEffect, useRef } from "react";
import { useFormContext, useWatch } from "react-hook-form";
import { describe, expect, it } from "vitest";
@@ -69,4 +70,24 @@ describe("ConditionalPublicModelName", () => {
expect(screen.getByText("my-custom-model")).toBeInTheDocument();
expect(screen.queryByDisplayValue("custom")).not.toBeInTheDocument();
});
+
+ it("keeps the public name input focused across keystrokes", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ const input = screen.getByDisplayValue("gpt-4");
+ await user.type(input, "-prod");
+
+ expect(input).toHaveValue("gpt-4-prod");
+ expect(input).toHaveFocus();
+ });
});
diff --git a/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.tsx b/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.tsx
index c58b177a6e1..f83ace0dbfb 100644
--- a/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.tsx
+++ b/ui/litellm-dashboard/src/components/add_model/conditional_public_model_name.tsx
@@ -36,6 +36,87 @@ const modelMappingsRule = {
const tooltipCodeClassName = "rounded-sm bg-background/20 px-1 py-0.5 font-mono text-xs";
+const ANTHROPIC_1M_HEADERS = JSON.stringify(
+ { extra_headers: { "anthropic-beta": "context-1m-2025-08-07" } },
+ null,
+ 2,
+);
+
+const publicNameTooltipContent = (
+
+
The name you specify in your API calls to LiteLLM Proxy
+
+ Example: If you name your public model{" "}
+ example-name, and choose{" "}
+ openai/qwen-plus-latest as the LiteLLM model
+
+
+ Usage: You make an API call to the LiteLLM proxy with{" "}
+ model = "example-name"
+
+
+ Result: LiteLLM sends qwen-plus-latest to the
+ provider
+
+
+);
+
+const PublicNameInput: React.FC<{ readonly index: number; readonly value: string }> = ({ index, value }) => {
+ const form = useFormContext();
+ const selectedProvider = useWatch({ control: form.control, name: "custom_llm_provider" });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ const typed = event.target.value;
+ const litellmParams = form.getValues("litellm_extra_params") as string | undefined;
+ const wantsAnthropic1m =
+ selectedProvider === Providers.Anthropic && typed.endsWith("-1m") && (litellmParams ?? "").trim() === "";
+
+ if (wantsAnthropic1m) {
+ form.setValue("litellm_extra_params", ANTHROPIC_1M_HEADERS);
+ }
+
+ const publicName = wantsAnthropic1m ? typed.slice(0, -"-1m".length) : typed;
+ const current = (form.getValues("model_mappings") as ModelMapping[]) ?? [];
+ form.setValue(
+ "model_mappings",
+ current.map((mapping, mappingIndex) =>
+ mappingIndex === index ? { ...mapping, public_name: publicName } : mapping,
+ ),
+ );
+ };
+
+ return ;
+};
+
+/**
+ * Module-level so the header and cell renderers keep a stable identity: React treats a renderer
+ * declared inside the component as a new element type on every render and remounts the input,
+ * which drops focus after each keystroke.
+ */
+const columns: ColumnDef[] = [
+ {
+ id: "public_name",
+ accessorKey: "public_name",
+ header: () => (
+
+ Public Model Name
+
+
+ ),
+ cell: ({ row }) => ,
+ },
+ {
+ id: "litellm_model",
+ accessorKey: "litellm_model",
+ header: () => (
+
+ LiteLLM Model Name
+ The model name LiteLLM will send to the LLM API} width="360px" />
+
+ ),
+ },
+];
+
const ConditionalPublicModelName: React.FC = () => {
const form = useFormContext();
@@ -124,85 +205,6 @@ const ConditionalPublicModelName: React.FC = () => {
if (!showPublicModelName) return null;
- const publicNameTooltipContent = (
-
-
The name you specify in your API calls to LiteLLM Proxy
-
- Example: If you name your public model{" "}
- example-name, and choose{" "}
- openai/qwen-plus-latest as the LiteLLM model
-
-
- Usage: You make an API call to the LiteLLM proxy with{" "}
- model = "example-name"
-
-
- Result: LiteLLM sends qwen-plus-latest to the
- provider
-
-
- );
-
- const liteLLMModelTooltipContent = The model name LiteLLM will send to the LLM API
;
-
- const columns: ColumnDef[] = [
- {
- id: "public_name",
- accessorKey: "public_name",
- header: () => (
-
- Public Model Name
-
-
- ),
- cell: ({ row }) => {
- return (
- {
- const newValue = e.target.value;
- const newMappings = [...((form.getValues("model_mappings") as ModelMapping[]) ?? [])];
-
- // Check conditions for Anthropic -1m suffix handling
- const isAnthropic = selectedProvider === Providers.Anthropic;
- const endsWith1m = newValue.endsWith("-1m");
- const litellmParams = form.getValues("litellm_extra_params") as string | undefined;
- const isLitellmParamsEmpty = !litellmParams || litellmParams.trim() === "";
-
- let finalPublicName = newValue;
-
- if (isAnthropic && endsWith1m && isLitellmParamsEmpty) {
- // Set litellm params with extra_headers
- const litellmParamsValue = JSON.stringify(
- { extra_headers: { "anthropic-beta": "context-1m-2025-08-07" } },
- null,
- 2,
- );
- form.setValue("litellm_extra_params", litellmParamsValue);
-
- // Remove -1m suffix from public_name
- finalPublicName = newValue.slice(0, -3); // Remove "-1m" (3 characters)
- }
-
- newMappings[row.index].public_name = finalPublicName;
- form.setValue("model_mappings", newMappings);
- }}
- />
- );
- },
- },
- {
- id: "litellm_model",
- accessorKey: "litellm_model",
- header: () => (
-
- LiteLLM Model Name
-
-
- ),
- },
- ];
-
return (