Repository: pydantic/pydantic-ai
File: tests/models/test_model_names.py (Python)

Code before:
    cohere_names = [f'cohere:{n}' for n in get_model_names(CohereModelName)]
    google_names = [f'google-gla:{n}' for n in get_model_names(GoogleModelName)] + [
        f'google-vertex:{n}' for n in get_model_names(GoogleModelName)
    ]
    grok_names = [f'grok:{n}' for n in get_model_names(GrokModelName)]
    groq_names = [f'groq:{n}' for n in get_model_names(GroqModelName)]
    moonshotai_names = [f'moonshotai:{n}' for n in get_model_names(MoonshotAIModelName)]
    mistral_names = [f'mistral:{n}' for n in get_model_names(MistralModelName)]
    openai_names = [f'openai:{n}' for n in get_model_names(OpenAIModelName)]
    bedrock_names = [f'bedrock:{n}' for n in get_model_names(BedrockModelName)]
    deepseek_names = ['deepseek:deepseek-chat', 'deepseek:deepseek-reasoner']
    gateway_names = [
        'gateway/anthropic:claude-haiku-4-5',
        'gateway/anthropic:claude-opus-4-0',
        'gateway/anthropic:claude-sonnet-4-5',
        'gateway/bedrock:anthropic.claude-haiku-4-5-20251001-v1:0',
        'gateway/bedrock:anthropic.claude-opus-4-20250514-v1:0',
        'gateway/bedrock:anthropic.claude-sonnet-4-5-20250929-v1:0',
        'gateway/bedrock:us.amazon.nova-lite-v1:0',
        'gateway/bedrock:us.amazon.nova-micro-v1:0',
        'gateway/bedrock:us.amazon.nova-pro-v1:0',
        'gateway/google-vertex:gemini-2.5-flash',
        'gateway/google-vertex:gemini-2.5-flash-lite',
        'gateway/google-vertex:gemini-2.5-pro',
        'gateway/google-vertex:gemini-3-pro-preview',
        'gateway/groq:deepseek-r1-distill-llama-70b',
        'gateway/groq:gemma2-9b-it',
        'gateway/groq:llama-3.1-8b-instant',
        'gateway/groq:llama-3.3-70b-versatile',
        'gateway/groq:qwen-qwq-32b',
        'gateway/openai:gpt-5',
        'gateway/openai:gpt-5-mini',
        'gateway/openai:gpt-5-pro',
        'gateway/openai:o3',
        'gateway/openai:o4-mini',
    ]
    huggingface_names = [f'huggingface:{n}' for n in get_model_names(HuggingFaceModelName)]
    heroku_names = get_heroku_model_names()
    cerebras_names = get_cerebras_model_names()
    extra_names = ['test']

    generated_names = sorted(
        anthropic_names
        + cohere_names
        + google_names
        + grok_names
        + groq_names
        + mistral_names
        + moonshotai_names
        + openai_names
        + bedrock_names

Review comment (suggestion):
I realize you couldn't see this comment in a private Slack channel, but I responded to Samuel (and he agreed):

> Agreed, but if we add just a few per provider, people are definitely gonna ask us “but why not this other one?”, so maybe just include them all?

So we should NOT hard-code this, but dynamically build this based on the known model names of the providers that are known to work with `gateway/{provider}`

Code after:
    'groq': GroqModelName,
    'huggingface': HuggingFaceModelName,
    'mistral': MistralModelName,
    'moonshotai': MoonshotAIModelName,
    'openai': OpenAIModelName,
}


def test_known_model_names():  # pragma: lax no cover
    # Coverage seems to be misbehaving..?
    def get_model_names(model_name_type: Any) -> Iterator[str]:
        for arg in get_args(model_name_type):
            if isinstance(arg, str):
                yield arg
            else:
                yield from get_model_names(arg)

    all_generated_names = [
        f'{provider}:{n}'
        for provider, model_names in _PROVIDER_TO_MODEL_NAMES.items()
        for n in get_model_names(model_names)
    ]

    cerebras_names = get_cerebras_model_names()
    heroku_names = get_heroku_model_names()
    gateway_names = [
        f'gateway/{provider}:{model_name}'
        for provider in GatewayModelProvider.__args__
        for model_name in get_model_names(_PROVIDER_TO_MODEL_NAMES[provider])
    ]

    extra_names = ['test']

    generated_names = sorted(all_generated_names + gateway_names + heroku_names + cerebras_names + extra_names)

    known_model_names = sorted(get_args(KnownModelName.__value__))
    assert generated_names == known_model_names


class HerokuModel(TypedDict):
    model_id: str
    regions: list[str]
    type: list[str]


def get_heroku_model_names():
    response = httpx.get('https://us.inference.heroku.com/available-models')

    if response.status_code != 200:
        pytest.skip(f'Heroku AI returned status code {response.status_code}')  # pragma: lax no cover