Merge pull request #40170 from BerriAI/litellm_chatgpt_add_model_provider

feat(ui): list the ChatGPT subscription provider in the Add Model form
This commit is contained in:
ryan-crabbe-berri 2026-09-07 15:21:58 -07:00 committed by GitHub
commit 38683643e0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 105 additions and 0 deletions

View file

@ -688,6 +688,13 @@
],
"default_model_placeholder": "gpt-3.5-turbo"
},
{
"provider": "CHATGPT",
"provider_display_name": "ChatGPT Subscription",
"litellm_provider": "chatgpt",
"credential_fields": [],
"default_model_placeholder": "chatgpt/gpt-5.4"
},
{
"provider": "CLARIFAI",
"provider_display_name": "Clarifai",

View file

@ -1,5 +1,6 @@
import re
from datetime import datetime, timezone
from typing import Final
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
@ -327,6 +328,85 @@ def test_cognition_provider_fields():
assert fields_by_key["api_base"]["required"] is False
def test_chatgpt_provider_fields():
app_instance = FastAPI()
app_instance.include_router(router)
test_client = TestClient(app_instance)
response = test_client.get("/public/providers/fields")
assert response.status_code == 200
providers = response.json()
chatgpt = next((p for p in providers if p["provider"] == "CHATGPT"), None)
assert chatgpt is not None, "ChatGPT provider entry not found"
assert chatgpt["provider_display_name"] == "ChatGPT Subscription"
assert chatgpt["litellm_provider"] == LlmProviders.CHATGPT.value
assert chatgpt["default_model_placeholder"].startswith("chatgpt/")
assert chatgpt["credential_fields"] == []
ADD_MODEL_UNLISTED_PROVIDERS: Final = frozenset(
{
"a2a",
"a2a_agent",
"amazon_nova",
"apertis",
"aws_polly",
"black_forest_labs",
"charity_engine",
"chutes",
"darkbloom",
"gdc",
"helicone",
"inception",
"langflow",
"langgraph",
"libertai",
"litellm_agent",
"manus",
"meta",
"modelscope",
"mongodb",
"nano-gpt",
"neosantara",
"parasail",
"pinstripes",
"poe",
"publicai",
"ragflow",
"reducto",
"s3_vectors",
"sagemaker_nova",
"scaleway",
"stability",
"synthetic",
"tencent",
"tensormesh",
"text-completion-inception",
"valkey",
"xiaomi_mimo",
"zai",
}
)
def test_every_backend_provider_is_listed_in_add_model_or_frozen_as_unlisted():
app_instance = FastAPI()
app_instance.include_router(router)
test_client = TestClient(app_instance)
response = test_client.get("/public/providers/fields")
assert response.status_code == 200
listed = {p["litellm_provider"] for p in response.json()}
unlisted = {provider.value for provider in LlmProviders} - listed
assert unlisted == ADD_MODEL_UNLISTED_PROVIDERS, (
"Add Model dropdown drift: give the new provider an entry in provider_create_fields.json "
"rather than adding it to ADD_MODEL_UNLISTED_PROVIDERS"
)
def test_google_ai_studio_provider_fields_expose_api_base():
"""The Google AI Studio (gemini) credential form must let admins set a custom
api_base so they can point at a Gemini-compatible gateway (e.g. a self-hosted

View file

@ -89,6 +89,16 @@ describe("provider_info_helpers", () => {
expect(result.logo).toBe(providerLogoMap[Providers.BedrockMantle]);
});
it("should map the chatgpt slug and CHATGPT enum key to the ChatGPT Subscription name and OpenAI logo", () => {
const fromSlug = getProviderLogoAndName("chatgpt");
expect(fromSlug.displayName).toBe("ChatGPT Subscription");
expect(fromSlug.logo).toContain("openai_small");
const fromEnumKey = getProviderLogoAndName("CHATGPT");
expect(fromEnumKey.displayName).toBe("ChatGPT Subscription");
expect(fromEnumKey.logo).toContain("openai_small");
});
it("should handle provider values case-insensitively", () => {
const result = getProviderLogoAndName("OPENAI");
expect(result.displayName).toBe(Providers.OpenAI);
@ -272,6 +282,10 @@ describe("provider_info_helpers", () => {
expect(getPlaceholder(Providers.Cognition)).toBe("cognition/swe-1.7");
});
it("should return a chatgpt/ placeholder for the CHATGPT dropdown key", () => {
expect(getPlaceholder("CHATGPT")).toBe("chatgpt/gpt-5.4");
});
it("should return default gpt-3.5-turbo placeholder for unknown provider", () => {
expect(getPlaceholder("UnknownProvider" as any)).toBe("gpt-3.5-turbo");
});

View file

@ -84,6 +84,7 @@ export enum Providers {
BASETEN = "Baseten",
BYTEZ = "Bytez",
Cerebras = "Cerebras",
CHATGPT = "ChatGPT Subscription",
CLARIFAI = "Clarifai",
CLOUDFLARE = "Cloudflare",
CODESTRAL = "Codestral",
@ -198,6 +199,7 @@ export const provider_map: Record<string, string> = {
BedrockMantle: "bedrock_mantle",
BYTEZ: "bytez",
Cerebras: "cerebras",
CHATGPT: "chatgpt",
CLARIFAI: "clarifai",
CLOUDFLARE: "cloudflare",
CODESTRAL: "codestral",
@ -314,6 +316,7 @@ export const providerLogoMap: Partial<Record<Providers, string>> = {
[Providers.BedrockMantle]: bedrockLogo.src,
[Providers.SageMaker]: bedrockLogo.src,
[Providers.Cerebras]: cerebrasLogo.src,
[Providers.CHATGPT]: openaiSmallLogo.src,
[Providers.CLOUDFLARE]: cloudflareLogo.src,
[Providers.CODESTRAL]: mistralLogo.src,
[Providers.Cohere]: cohereLogo.src,
@ -425,6 +428,7 @@ const providerPlaceholderMap: Partial<Record<Providers, string>> = {
[Providers.Azure]: "my-deployment",
[Providers.Azure_AI_Studio]: "azure_ai/command-r-plus",
[Providers.Bedrock]: "claude-3-opus",
[Providers.CHATGPT]: "chatgpt/gpt-5.4",
[Providers.Cognition]: "cognition/swe-1.7",
[Providers.Cursor]: "cursor/claude-4-sonnet",
[Providers.DeepInfra]: "deepinfra/<any-model-on-deepinfra>",